Merge branch release-2016
authorTeemu Murtola <teemu.murtola@gmail.com>
Mon, 12 Dec 2016 19:39:12 +0000 (21:39 +0200)
committerTeemu Murtola <teemu.murtola@gmail.com>
Mon, 12 Dec 2016 20:36:50 +0000 (22:36 +0200)
Conflicts:
    cmake/gmxVersionInfo.cmake

Add a suppression for Intel compiler warning in generated code in
scanner.cpp.

Change-Id: I3a6310c433a50202fbc76e53570a491bd3d06544

582 files changed:
CMakeLists.txt
INSTALL-dev [new file with mode: 0644]
admin/builds/coverage.py
admin/builds/cppcheck.py
admin/builds/gromacs.py
admin/builds/pre-submit-matrix.txt
admin/builds/regressiontests-update.py
admin/builds/release-matrix.txt
cmake/TestAVXMaskload.c [deleted file]
cmake/TestClangVersion.c [deleted file]
cmake/gmxBuildTypeASAN.cmake
cmake/gmxBuildTypeReference.cmake
cmake/gmxCFlags.cmake
cmake/gmxCPackUtilities.cmake
cmake/gmxCTestUtilities.cmake [new file with mode: 0644]
cmake/gmxCustomCommandUtilities.cmake
cmake/gmxManageGPU.cmake
cmake/gmxManageLinearAlgebraLibraries.cmake
cmake/gmxManageMPI.cmake
cmake/gmxManageNvccConfig.cmake
cmake/gmxManageOpenMP.cmake
cmake/gmxManageSimd.cmake
cmake/gmxManageTNG.cmake
cmake/gmxTestAVXMaskload.cmake [deleted file]
cmake/gmxTestCXX11.cmake
cmake/gmxTestCompilerProblems.cmake
cmake/gmxVersionInfo.cmake
cmake/with_asan_opts.sh [new file with mode: 0755]
docs/CMakeLists.txt
docs/conf-vars.py.cmakein
docs/conf.py
docs/dev-manual/build-system.rst
docs/dev-manual/language-features.rst
docs/doxygen/CMakeLists.txt
docs/doxygen/includesorter.py
docs/doxygen/lib/logging.md [new file with mode: 0644]
docs/doxygen/lib/refdata.md
docs/doxygen/suppressions.txt
docs/doxygen/user/mainpage.md
docs/install-guide/index.rst
docs/manual/forcefield.tex
docs/manual/monster.bib
docs/manual/plots/field.eps [new file with mode: 0644]
docs/manual/plots/field.xvg [new file with mode: 0644]
docs/manual/special.tex
docs/user-guide/cmdline.rst
share/template/CMakeLists.txt.template
src/CMakeLists.txt
src/config.h.cmakein
src/external/gmock-1.7.0/CMakeLists.txt
src/external/thread_mpi/include/thread_mpi/tmpi.h
src/external/thread_mpi/src/gather.c
src/external/thread_mpi/src/p2p_send_recv.c
src/external/thread_mpi/src/scatter.c
src/external/tng_io/BuildTNG.cmake
src/external/tng_io/CMakeLists.txt
src/external/tng_io/external/README [new file with mode: 0644]
src/external/tng_io/external/zlib/README [new file with mode: 0644]
src/external/tng_io/external/zlib/adler32.c [new file with mode: 0644]
src/external/tng_io/external/zlib/compress.c [new file with mode: 0644]
src/external/tng_io/external/zlib/crc32.c [new file with mode: 0644]
src/external/tng_io/external/zlib/crc32.h [new file with mode: 0644]
src/external/tng_io/external/zlib/deflate.c [new file with mode: 0644]
src/external/tng_io/external/zlib/deflate.h [new file with mode: 0644]
src/external/tng_io/external/zlib/inffast.c [new file with mode: 0644]
src/external/tng_io/external/zlib/inffast.h [new file with mode: 0644]
src/external/tng_io/external/zlib/inffixed.h [new file with mode: 0644]
src/external/tng_io/external/zlib/inflate.c [new file with mode: 0644]
src/external/tng_io/external/zlib/inflate.h [new file with mode: 0644]
src/external/tng_io/external/zlib/inftrees.c [new file with mode: 0644]
src/external/tng_io/external/zlib/inftrees.h [new file with mode: 0644]
src/external/tng_io/external/zlib/trees.c [new file with mode: 0644]
src/external/tng_io/external/zlib/trees.h [new file with mode: 0644]
src/external/tng_io/external/zlib/uncompr.c [new file with mode: 0644]
src/external/tng_io/external/zlib/zconf.h [new file with mode: 0644]
src/external/tng_io/external/zlib/zlib.h [new file with mode: 0644]
src/external/tng_io/external/zlib/zutil.c [new file with mode: 0644]
src/external/tng_io/external/zlib/zutil.h [new file with mode: 0644]
src/external/tng_io/include/tng/tng_io.h
src/external/tng_io/src/lib/tng_io-config.cmake.in
src/external/tng_io/src/lib/tng_io.c
src/external/tng_io/src/lib/tng_io_fortran.c
src/external/tng_io/src/tests/CMakeLists.txt
src/external/tng_io/src/tests/md_openmp.f
src/external/tng_io/src/tests/tng_io_testing.c
src/external/tng_io/src/tests/using/CMakeLists.txt [new file with mode: 0644]
src/external/tng_io/src/tests/using/dummy_zlib.c [new file with mode: 0644]
src/external/tng_io/src/tests/using/main.c [new file with mode: 0644]
src/external/tng_io/src/tests/using/use_tng.c [new file with mode: 0644]
src/external/tng_io/src/tests/using/use_zlib.c [new file with mode: 0644]
src/gromacs/CMakeLists.txt
src/gromacs/analysisdata/analysisdata.cpp
src/gromacs/analysisdata/analysisdata.h
src/gromacs/analysisdata/datamodulemanager.cpp
src/gromacs/analysisdata/datastorage.cpp
src/gromacs/analysisdata/modules/displacement.cpp
src/gromacs/analysisdata/modules/lifetime.cpp
src/gromacs/analysisdata/modules/plot.cpp
src/gromacs/analysisdata/tests/datatest.h
src/gromacs/applied-forces/CMakeLists.txt [new file with mode: 0644]
src/gromacs/applied-forces/electricfield.cpp [new file with mode: 0644]
src/gromacs/applied-forces/electricfield.h [new file with mode: 0644]
src/gromacs/applied-forces/tests/CMakeLists.txt [new file with mode: 0644]
src/gromacs/applied-forces/tests/electricfield.cpp [new file with mode: 0644]
src/gromacs/commandline/cmdlinehelpmodule.cpp
src/gromacs/commandline/cmdlinehelpwriter.cpp
src/gromacs/commandline/cmdlinemodulemanager.cpp
src/gromacs/commandline/cmdlineoptionsmodule.cpp
src/gromacs/commandline/pargs.cpp
src/gromacs/commandline/shellcompletions.cpp
src/gromacs/commandline/tests/CMakeLists.txt
src/gromacs/commandline/tests/cmdlinehelpwriter.cpp
src/gromacs/commandline/tests/cmdlineparser.cpp
src/gromacs/commandline/tests/cmdlineprogramcontext.cpp
src/gromacs/commandline/tests/pargs.cpp
src/gromacs/correlationfunctions/autocorr.cpp
src/gromacs/correlationfunctions/manyautocorrelation.cpp
src/gromacs/correlationfunctions/manyautocorrelation.h
src/gromacs/correlationfunctions/tests/CMakeLists.txt
src/gromacs/correlationfunctions/tests/manyautocorrelation.cpp [new file with mode: 0644]
src/gromacs/domdec/domdec.cpp
src/gromacs/domdec/domdec.h
src/gromacs/domdec/domdec_constraints.cpp
src/gromacs/domdec/domdec_network.cpp
src/gromacs/domdec/domdec_network.h
src/gromacs/domdec/domdec_topology.cpp
src/gromacs/essentialdynamics/edsam.cpp
src/gromacs/essentialdynamics/edsam.h
src/gromacs/ewald/calculate-spline-moduli.cpp
src/gromacs/ewald/long-range-correction.cpp
src/gromacs/ewald/pme-grid.cpp
src/gromacs/ewald/pme-grid.h
src/gromacs/ewald/pme-internal.h
src/gromacs/ewald/pme-load-balancing.cpp
src/gromacs/ewald/pme-load-balancing.h
src/gromacs/ewald/pme-only.cpp
src/gromacs/ewald/pme-pp.cpp
src/gromacs/ewald/pme-solve.cpp
src/gromacs/ewald/pme-solve.h
src/gromacs/ewald/pme-spread.cpp
src/gromacs/ewald/pme.cpp
src/gromacs/ewald/pme.h
src/gromacs/fft/fft_fftpack.cpp
src/gromacs/fft/fft_mkl.cpp
src/gromacs/fileio/CMakeLists.txt
src/gromacs/fileio/checkpoint.cpp
src/gromacs/fileio/checkpoint.h
src/gromacs/fileio/confio.cpp
src/gromacs/fileio/confio.h
src/gromacs/fileio/enxio.cpp
src/gromacs/fileio/enxio.h
src/gromacs/fileio/espio.cpp
src/gromacs/fileio/espio.h
src/gromacs/fileio/g96io.cpp
src/gromacs/fileio/gmxfio-xdr.cpp
src/gromacs/fileio/gmxfio-xdr.h
src/gromacs/fileio/groio.cpp
src/gromacs/fileio/groio.h
src/gromacs/fileio/oenv.cpp
src/gromacs/fileio/pdbio.cpp
src/gromacs/fileio/pdbio.h
src/gromacs/fileio/readinp.cpp
src/gromacs/fileio/readinp.h
src/gromacs/fileio/tests/confio.cpp
src/gromacs/fileio/tests/tngio.cpp
src/gromacs/fileio/tngio.cpp
src/gromacs/fileio/tngio.h
src/gromacs/fileio/tngio_for_tools.cpp [deleted file]
src/gromacs/fileio/tngio_for_tools.h [deleted file]
src/gromacs/fileio/tpxio.cpp
src/gromacs/fileio/trxio.cpp
src/gromacs/fileio/xvgr.cpp
src/gromacs/gmxana/binsearch.cpp
src/gromacs/gmxana/edittop.cpp
src/gromacs/gmxana/gmx_anaeig.cpp
src/gromacs/gmxana/gmx_analyze.cpp
src/gromacs/gmxana/gmx_angle.cpp
src/gromacs/gmxana/gmx_chi.cpp
src/gromacs/gmxana/gmx_cluster.cpp
src/gromacs/gmxana/gmx_clustsize.cpp
src/gromacs/gmxana/gmx_confrms.cpp
src/gromacs/gmxana/gmx_dipoles.cpp
src/gromacs/gmxana/gmx_disre.cpp
src/gromacs/gmxana/gmx_dos.cpp
src/gromacs/gmxana/gmx_dyndom.cpp
src/gromacs/gmxana/gmx_editconf.cpp
src/gromacs/gmxana/gmx_energy.cpp
src/gromacs/gmxana/gmx_gyrate.cpp
src/gromacs/gmxana/gmx_hbond.cpp
src/gromacs/gmxana/gmx_make_ndx.cpp
src/gromacs/gmxana/gmx_mindist.cpp
src/gromacs/gmxana/gmx_nmeig.cpp
src/gromacs/gmxana/gmx_pme_error.cpp
src/gromacs/gmxana/gmx_rmsf.cpp
src/gromacs/gmxana/gmx_rotacf.cpp
src/gromacs/gmxana/gmx_spol.cpp
src/gromacs/gmxana/gmx_tcaf.cpp
src/gromacs/gmxana/gmx_traj.cpp
src/gromacs/gmxana/gmx_trjcat.cpp
src/gromacs/gmxana/gmx_trjconv.cpp
src/gromacs/gmxana/gmx_tune_pme.cpp
src/gromacs/gmxana/gmx_velacc.cpp
src/gromacs/gmxana/gmx_wham.cpp
src/gromacs/gmxana/legacytests/CMakeLists.txt
src/gromacs/gmxana/legacytests/gmx_traj_tests.cpp
src/gromacs/gmxana/nrama.cpp
src/gromacs/gmxana/nsfactor.cpp
src/gromacs/gmxlib/network.cpp
src/gromacs/gmxlib/network.h
src/gromacs/gmxlib/nonbonded/nb_kernel_avx_128_fma_single/kernelutil_x86_avx_128_fma_single.h
src/gromacs/gmxlib/nonbonded/nb_kernel_avx_256_single/kernelutil_x86_avx_256_single.h
src/gromacs/gmxpreprocess/convparm.cpp
src/gromacs/gmxpreprocess/gen_ad.cpp
src/gromacs/gmxpreprocess/gen_maxwell_velocities.cpp
src/gromacs/gmxpreprocess/genconf.cpp
src/gromacs/gmxpreprocess/grompp-impl.h
src/gromacs/gmxpreprocess/grompp.cpp
src/gromacs/gmxpreprocess/h_db.cpp
src/gromacs/gmxpreprocess/insert-molecules.cpp
src/gromacs/gmxpreprocess/pdb2top.cpp
src/gromacs/gmxpreprocess/read-conformation.cpp
src/gromacs/gmxpreprocess/read-conformation.h
src/gromacs/gmxpreprocess/readir.cpp
src/gromacs/gmxpreprocess/readpull.cpp
src/gromacs/gmxpreprocess/resall.cpp
src/gromacs/gmxpreprocess/topio.cpp
src/gromacs/gpu_utils/cudautils.cu
src/gromacs/gpu_utils/cudautils.cuh
src/gromacs/gpu_utils/gpu_utils.cu
src/gromacs/gpu_utils/gpu_utils.h
src/gromacs/gpu_utils/gpu_utils_ocl.cpp
src/gromacs/gromacs-config.cmake.cmakein
src/gromacs/hardware/CMakeLists.txt
src/gromacs/hardware/detecthardware.cpp
src/gromacs/hardware/detecthardware.h
src/gromacs/hardware/hardwareassign.cpp [new file with mode: 0644]
src/gromacs/hardware/hardwareassign.h [moved from src/gromacs/gmxlib/md_logging.h with 64% similarity]
src/gromacs/hardware/hardwaretopology.cpp
src/gromacs/hardware/hardwaretopology.h
src/gromacs/imd/imd.cpp
src/gromacs/linearalgebra/gmx_arpack.cpp
src/gromacs/linearalgebra/gmx_lapack/dbdsqr.cpp
src/gromacs/linearalgebra/gmx_lapack/dstebz.cpp
src/gromacs/linearalgebra/gmx_lapack/sbdsqr.cpp
src/gromacs/linearalgebra/gmx_lapack/sstebz.cpp
src/gromacs/listed-forces/CMakeLists.txt
src/gromacs/listed-forces/orires.cpp
src/gromacs/listed-forces/position-restraints.cpp
src/gromacs/listed-forces/tests/CMakeLists.txt [new file with mode: 0644]
src/gromacs/listed-forces/tests/bonded.cpp [new file with mode: 0644]
src/gromacs/listed-forces/tests/refdata/BondedTest_BondAnglePbcNone.xml [new file with mode: 0644]
src/gromacs/listed-forces/tests/refdata/BondedTest_BondAnglePbcXy.xml [new file with mode: 0644]
src/gromacs/listed-forces/tests/refdata/BondedTest_BondAnglePbcXyz.xml [new file with mode: 0644]
src/gromacs/listed-forces/tests/refdata/BondedTest_DihedarlAnglePbcXyz.xml [new file with mode: 0644]
src/gromacs/listed-forces/tests/refdata/BondedTest_DihedralAnglePbcNone.xml [new file with mode: 0644]
src/gromacs/listed-forces/tests/refdata/BondedTest_DihedralAnglePbcXy.xml [new file with mode: 0644]
src/gromacs/listed-forces/tests/refdata/BondedTest_IfuncAnglesPbcNo.xml [new file with mode: 0644]
src/gromacs/listed-forces/tests/refdata/BondedTest_IfuncAnglesPbcXYZ.xml [new file with mode: 0644]
src/gromacs/listed-forces/tests/refdata/BondedTest_IfuncAnglesPbcXy.xml [new file with mode: 0644]
src/gromacs/listed-forces/tests/refdata/BondedTest_IfuncBondsPbcNo.xml [new file with mode: 0644]
src/gromacs/listed-forces/tests/refdata/BondedTest_IfuncBondsPbcXy.xml [new file with mode: 0644]
src/gromacs/listed-forces/tests/refdata/BondedTest_IfuncBondsPbcXyz.xml [new file with mode: 0644]
src/gromacs/listed-forces/tests/refdata/BondedTest_IfuncProperDihedralsPbcNo.xml [new file with mode: 0644]
src/gromacs/listed-forces/tests/refdata/BondedTest_IfuncProperDihedralsPbcXy.xml [new file with mode: 0644]
src/gromacs/listed-forces/tests/refdata/BondedTest_IfuncProperDihedralsPbcXyz.xml [new file with mode: 0644]
src/gromacs/math/CMakeLists.txt
src/gromacs/math/paddedvector.h [new file with mode: 0644]
src/gromacs/math/tests/vectypes.cpp
src/gromacs/math/veccompare.cpp [new file with mode: 0644]
src/gromacs/math/veccompare.h [moved from src/gromacs/tools/compare.h with 70% similarity]
src/gromacs/math/vecdump.cpp
src/gromacs/math/vecdump.h
src/gromacs/math/vectypes.h
src/gromacs/mdlib/broadcaststructs.cpp
src/gromacs/mdlib/broadcaststructs.h [new file with mode: 0644]
src/gromacs/mdlib/constr.cpp
src/gromacs/mdlib/constr.h
src/gromacs/mdlib/coupling.cpp
src/gromacs/mdlib/csettle.cpp
src/gromacs/mdlib/force.cpp
src/gromacs/mdlib/force.h
src/gromacs/mdlib/forcerec.cpp
src/gromacs/mdlib/forcerec.h
src/gromacs/mdlib/gmx_omp_nthreads.cpp
src/gromacs/mdlib/gmx_omp_nthreads.h
src/gromacs/mdlib/integrator.h
src/gromacs/mdlib/md_support.cpp
src/gromacs/mdlib/md_support.h
src/gromacs/mdlib/mdatoms.cpp
src/gromacs/mdlib/mdatoms.h
src/gromacs/mdlib/mdebin.cpp
src/gromacs/mdlib/mdebin.h
src/gromacs/mdlib/mdebin_bar.cpp
src/gromacs/mdlib/mdebin_bar.h
src/gromacs/mdlib/mdoutf.cpp
src/gromacs/mdlib/mdoutf.h
src/gromacs/mdlib/mdsetup.cpp [new file with mode: 0644]
src/gromacs/mdlib/mdsetup.h [new file with mode: 0644]
src/gromacs/mdlib/minimize.cpp
src/gromacs/mdlib/nbnxn_cuda/nbnxn_cuda.cu
src/gromacs/mdlib/nbnxn_kernels/nbnxn_kernel_ref_inner.h
src/gromacs/mdlib/qmmm.cpp
src/gromacs/mdlib/shellfc.cpp
src/gromacs/mdlib/shellfc.h
src/gromacs/mdlib/sim_util.cpp
src/gromacs/mdlib/sim_util.h
src/gromacs/mdlib/simulationsignal.h
src/gromacs/mdlib/tests/settle.cpp
src/gromacs/mdlib/tgroup.cpp
src/gromacs/mdlib/tpi.cpp
src/gromacs/mdlib/trajectory_writing.cpp
src/gromacs/mdlib/trajectory_writing.h
src/gromacs/mdlib/update.cpp
src/gromacs/mdlib/update.h
src/gromacs/mdrunutility/CMakeLists.txt
src/gromacs/mdrunutility/mdmodules.cpp [new file with mode: 0644]
src/gromacs/mdrunutility/mdmodules.h [new file with mode: 0644]
src/gromacs/mdrunutility/tests/CMakeLists.txt [new file with mode: 0644]
src/gromacs/mdrunutility/tests/threadaffinity.cpp [new file with mode: 0644]
src/gromacs/mdrunutility/tests/threadaffinitytest.cpp [new file with mode: 0644]
src/gromacs/mdrunutility/tests/threadaffinitytest.h [new file with mode: 0644]
src/gromacs/mdrunutility/threadaffinity.cpp
src/gromacs/mdrunutility/threadaffinity.h
src/gromacs/mdtypes/energyhistory.h
src/gromacs/mdtypes/forcerec.h
src/gromacs/mdtypes/inputrec.cpp
src/gromacs/mdtypes/inputrec.h
src/gromacs/mdtypes/mdatom.h
src/gromacs/mdtypes/state.cpp
src/gromacs/mdtypes/state.h
src/gromacs/onlinehelp/helpformat.cpp
src/gromacs/onlinehelp/helpwritercontext.cpp
src/gromacs/onlinehelp/tests/CMakeLists.txt
src/gromacs/options/CMakeLists.txt
src/gromacs/options/abstractoption.cpp
src/gromacs/options/abstractoption.h
src/gromacs/options/abstractoptionstorage.h
src/gromacs/options/abstractsection.cpp [new file with mode: 0644]
src/gromacs/options/abstractsection.h [new file with mode: 0644]
src/gromacs/options/basicoptions.cpp
src/gromacs/options/basicoptions.h
src/gromacs/options/basicoptionstorage.h
src/gromacs/options/filenameoption.cpp
src/gromacs/options/filenameoptionstorage.h
src/gromacs/options/ioptionscontainer.h
src/gromacs/options/ioptionscontainerwithsections.h [new file with mode: 0644]
src/gromacs/options/isectionstorage.h [new file with mode: 0644]
src/gromacs/options/ivaluestore.h [new file with mode: 0644]
src/gromacs/options/options-impl.h
src/gromacs/options/options.cpp
src/gromacs/options/options.h
src/gromacs/options/optionsassigner.cpp
src/gromacs/options/optionsassigner.h
src/gromacs/options/optionsection.cpp [new file with mode: 0644]
src/gromacs/options/optionsection.h [new file with mode: 0644]
src/gromacs/options/optionstoragetemplate.h
src/gromacs/options/optionsvisitor.cpp
src/gromacs/options/optionsvisitor.h
src/gromacs/options/repeatingsection.h [new file with mode: 0644]
src/gromacs/options/tests/CMakeLists.txt
src/gromacs/options/tests/abstractoptionstorage.cpp
src/gromacs/options/tests/filenameoption.cpp
src/gromacs/options/tests/filenameoptionmanager.cpp
src/gromacs/options/tests/option.cpp
src/gromacs/options/tests/optionsassigner.cpp
src/gromacs/options/tests/refdata/TreeValueSupportAdjustTest_FillsDefaultObjectValues.xml [new file with mode: 0644]
src/gromacs/options/tests/refdata/TreeValueSupportAdjustTest_FillsDefaultValues.xml [new file with mode: 0644]
src/gromacs/options/tests/refdata/TreeValueSupportAdjustTest_FillsDefaultVectorValues.xml [new file with mode: 0644]
src/gromacs/options/tests/refdata/TreeValueSupportAdjustTest_MergesDefaultValues.xml [new file with mode: 0644]
src/gromacs/options/tests/refdata/TreeValueSupportAdjustTest_NormalizesValues.xml [new file with mode: 0644]
src/gromacs/options/tests/refdata/TreeValueSupportAdjustTest_OrdersValues.xml [new file with mode: 0644]
src/gromacs/options/tests/repeatingsection.cpp [new file with mode: 0644]
src/gromacs/options/tests/timeunitmanager.cpp
src/gromacs/options/tests/treesupport.cpp [new file with mode: 0644]
src/gromacs/options/timeunitmanager.cpp
src/gromacs/options/treesupport.cpp [new file with mode: 0644]
src/gromacs/options/treesupport.h [new file with mode: 0644]
src/gromacs/options/valueconverter.h [new file with mode: 0644]
src/gromacs/options/valuestore.h [new file with mode: 0644]
src/gromacs/pbcutil/boxutilities.cpp
src/gromacs/pbcutil/boxutilities.h
src/gromacs/pbcutil/pbc.cpp
src/gromacs/pbcutil/pbc.h
src/gromacs/pulling/pull.cpp
src/gromacs/pulling/pull_rotation.cpp
src/gromacs/random/gammadistribution.h
src/gromacs/selection/centerofmass.cpp
src/gromacs/selection/centerofmass.h
src/gromacs/selection/compiler.cpp
src/gromacs/selection/evaluate.cpp
src/gromacs/selection/evaluate.h
src/gromacs/selection/indexutil.cpp
src/gromacs/selection/indexutil.h
src/gromacs/selection/parser.cpp
src/gromacs/selection/parser.h
src/gromacs/selection/parser.patch
src/gromacs/selection/parser.y
src/gromacs/selection/poscalc.cpp
src/gromacs/selection/poscalc.h
src/gromacs/selection/scanner.cpp
src/gromacs/selection/scanner.l
src/gromacs/selection/scanner_flex.h
src/gromacs/selection/selection.cpp
src/gromacs/selection/selection.h
src/gromacs/selection/selectioncollection-impl.h
src/gromacs/selection/selectioncollection.cpp
src/gromacs/selection/selectioncollection.h
src/gromacs/selection/selectionenums.h
src/gromacs/selection/selectionfileoptionstorage.h
src/gromacs/selection/selectionoption.cpp
src/gromacs/selection/selectionoptionbehavior.cpp
src/gromacs/selection/selectionoptionbehavior.h
src/gromacs/selection/selectionoptionmanager.cpp
src/gromacs/selection/selectionoptionstorage.h
src/gromacs/selection/selelem.cpp
src/gromacs/selection/selelem.h
src/gromacs/selection/selmethod.h
src/gromacs/selection/sm_compare.cpp
src/gromacs/selection/sm_distance.cpp
src/gromacs/selection/sm_insolidangle.cpp
src/gromacs/selection/sm_keywords.cpp
src/gromacs/selection/sm_merge.cpp
src/gromacs/selection/sm_permute.cpp
src/gromacs/selection/sm_position.cpp
src/gromacs/selection/sm_same.cpp
src/gromacs/selection/sm_simple.cpp
src/gromacs/selection/tests/indexutil.cpp
src/gromacs/selection/tests/nbsearch.cpp
src/gromacs/selection/tests/poscalc.cpp
src/gromacs/selection/tests/selectioncollection.cpp
src/gromacs/selection/tests/selectionoption.cpp
src/gromacs/selection/tests/toputils.cpp
src/gromacs/selection/tests/toputils.h
src/gromacs/simd/impl_ibm_qpx/impl_ibm_qpx_general.h
src/gromacs/simd/impl_ibm_qpx/impl_ibm_qpx_simd4_double.h
src/gromacs/simd/impl_x86_avx_128_fma/impl_x86_avx_128_fma_definitions.h
src/gromacs/swap/swapcoords.cpp
src/gromacs/swap/swapcoords.h
src/gromacs/tables/CMakeLists.txt
src/gromacs/tables/cubicsplinetable.cpp [new file with mode: 0644]
src/gromacs/tables/cubicsplinetable.h [new file with mode: 0644]
src/gromacs/tables/forcetable.h
src/gromacs/tables/quadraticsplinetable.cpp [new file with mode: 0644]
src/gromacs/tables/quadraticsplinetable.h [new file with mode: 0644]
src/gromacs/tables/splineutil.cpp [new file with mode: 0644]
src/gromacs/tables/splineutil.h [new file with mode: 0644]
src/gromacs/tables/tableinput.h [new file with mode: 0644]
src/gromacs/tables/tests/CMakeLists.txt [new file with mode: 0644]
src/gromacs/tables/tests/splinetable.cpp [new file with mode: 0644]
src/gromacs/timing/wallcycle.cpp
src/gromacs/timing/wallcyclereporting.h
src/gromacs/timing/walltime_accounting.cpp
src/gromacs/tools/check.cpp
src/gromacs/tools/compare.cpp [deleted file]
src/gromacs/tools/convert_tpr.cpp
src/gromacs/tools/dump.cpp
src/gromacs/topology/atoms.cpp
src/gromacs/topology/atoms.h
src/gromacs/topology/idef.cpp
src/gromacs/topology/idef.h
src/gromacs/topology/index.cpp
src/gromacs/topology/mtop_lookup.h [new file with mode: 0644]
src/gromacs/topology/mtop_util.cpp
src/gromacs/topology/mtop_util.h
src/gromacs/topology/symtab.cpp
src/gromacs/topology/topology.cpp
src/gromacs/topology/topology.h
src/gromacs/trajectory/CMakeLists.txt
src/gromacs/trajectory/trajectoryframe.cpp [new file with mode: 0644]
src/gromacs/trajectory/trajectoryframe.h
src/gromacs/trajectoryanalysis/analysismodule.cpp
src/gromacs/trajectoryanalysis/analysissettings.cpp
src/gromacs/trajectoryanalysis/analysissettings.h
src/gromacs/trajectoryanalysis/modules.cpp
src/gromacs/trajectoryanalysis/modules/distance.cpp
src/gromacs/trajectoryanalysis/modules/pairdist.cpp
src/gromacs/trajectoryanalysis/modules/rdf.cpp
src/gromacs/trajectoryanalysis/modules/sasa.cpp
src/gromacs/trajectoryanalysis/modules/select.cpp
src/gromacs/trajectoryanalysis/modules/trajectory.cpp [new file with mode: 0644]
src/gromacs/trajectoryanalysis/modules/trajectory.h [new file with mode: 0644]
src/gromacs/trajectoryanalysis/runnercommon.cpp
src/gromacs/trajectoryanalysis/tests/CMakeLists.txt
src/gromacs/trajectoryanalysis/tests/refdata/DistanceModuleTest_HandlesDynamicSelections.xml
src/gromacs/trajectoryanalysis/tests/refdata/TrajectoryModuleTest_BasicTest.xml [new file with mode: 0644]
src/gromacs/trajectoryanalysis/tests/refdata/TrajectoryModuleTest_HandlesNoForces.xml [new file with mode: 0644]
src/gromacs/trajectoryanalysis/tests/refdata/TrajectoryModuleTest_HandlesNoVelocities.xml [new file with mode: 0644]
src/gromacs/trajectoryanalysis/tests/refdata/TrajectoryModuleTest_PlotsXOnly.xml [new file with mode: 0644]
src/gromacs/trajectoryanalysis/tests/surfacearea.cpp
src/gromacs/trajectoryanalysis/tests/trajectory.cpp [new file with mode: 0644]
src/gromacs/utility.h
src/gromacs/utility/alignedallocator.h
src/gromacs/utility/arrayref.h
src/gromacs/utility/basedefinitions.h
src/gromacs/utility/classhelpers.h
src/gromacs/utility/compare.cpp [new file with mode: 0644]
src/gromacs/utility/compare.h [new file with mode: 0644]
src/gromacs/utility/coolstuff.cpp
src/gromacs/utility/datafilefinder.cpp
src/gromacs/utility/errorcodes.cpp
src/gromacs/utility/errorcodes.h
src/gromacs/utility/exceptions.cpp
src/gromacs/utility/exceptions.h
src/gromacs/utility/gmxmpi.h
src/gromacs/utility/ikeyvaluetreeerror.cpp [new file with mode: 0644]
src/gromacs/utility/ikeyvaluetreeerror.h [new file with mode: 0644]
src/gromacs/utility/iserializer.h [new file with mode: 0644]
src/gromacs/utility/keyvaluetree.cpp [new file with mode: 0644]
src/gromacs/utility/keyvaluetree.h [new file with mode: 0644]
src/gromacs/utility/keyvaluetreebuilder.h [new file with mode: 0644]
src/gromacs/utility/keyvaluetreeserializer.cpp [new file with mode: 0644]
src/gromacs/utility/keyvaluetreeserializer.h [new file with mode: 0644]
src/gromacs/utility/keyvaluetreetransform.cpp [new file with mode: 0644]
src/gromacs/utility/keyvaluetreetransform.h [new file with mode: 0644]
src/gromacs/utility/logger.cpp [moved from src/gromacs/gmxlib/md_logging.cpp with 60% similarity]
src/gromacs/utility/logger.h [new file with mode: 0644]
src/gromacs/utility/loggerbuilder.cpp [new file with mode: 0644]
src/gromacs/utility/loggerbuilder.h [new file with mode: 0644]
src/gromacs/utility/messagestringcollector.cpp
src/gromacs/utility/pleasecite.cpp
src/gromacs/utility/strconvert.cpp [new file with mode: 0644]
src/gromacs/utility/strconvert.h [new file with mode: 0644]
src/gromacs/utility/stringcompare.h [new file with mode: 0644]
src/gromacs/utility/stringutil.cpp
src/gromacs/utility/stringutil.h
src/gromacs/utility/tests/CMakeLists.txt
src/gromacs/utility/tests/arrayref.cpp
src/gromacs/utility/tests/keyvaluetreeserializer.cpp [new file with mode: 0644]
src/gromacs/utility/tests/keyvaluetreetransform.cpp [new file with mode: 0644]
src/gromacs/utility/tests/logger.cpp [new file with mode: 0644]
src/gromacs/utility/tests/refdata/KeyValueTreeSerializerTest_EmptyTree.xml [new file with mode: 0644]
src/gromacs/utility/tests/refdata/KeyValueTreeSerializerTest_ObjectWithArrays.xml [new file with mode: 0644]
src/gromacs/utility/tests/refdata/KeyValueTreeSerializerTest_ObjectWithObjects.xml [new file with mode: 0644]
src/gromacs/utility/tests/refdata/KeyValueTreeSerializerTest_SimpleObject.xml [new file with mode: 0644]
src/gromacs/utility/tests/refdata/LoggerTest_LevelFilteringWorks.xml [new file with mode: 0644]
src/gromacs/utility/tests/refdata/LoggerTest_LogsToFile.xml [new file with mode: 0644]
src/gromacs/utility/tests/refdata/LoggerTest_LogsToMultipleStreams.xml [new file with mode: 0644]
src/gromacs/utility/tests/refdata/LoggerTest_LogsToStream.xml [new file with mode: 0644]
src/gromacs/utility/tests/refdata/TreeValueTransformTest_ObjectFromMultipleStrings.xml [new file with mode: 0644]
src/gromacs/utility/tests/refdata/TreeValueTransformTest_ObjectFromString.xml [new file with mode: 0644]
src/gromacs/utility/tests/refdata/TreeValueTransformTest_SimpleTransforms.xml [new file with mode: 0644]
src/gromacs/utility/tests/refdata/TreeValueTransformTest_SimpleTransformsCaseAndDashInsensitive.xml [new file with mode: 0644]
src/gromacs/utility/tests/refdata/TreeValueTransformTest_SimpleTransformsToObject.xml [new file with mode: 0644]
src/gromacs/utility/tests/stringutil.cpp
src/gromacs/utility/variant.h [new file with mode: 0644]
src/programs/CMakeLists.txt
src/programs/mdrun/md.cpp
src/programs/mdrun/mdrun.cpp
src/programs/mdrun/membed.cpp
src/programs/mdrun/repl_ex.cpp
src/programs/mdrun/resource-division.cpp
src/programs/mdrun/resource-division.h
src/programs/mdrun/runner.cpp
src/programs/mdrun/tests/CMakeLists.txt
src/programs/mdrun/tests/moduletest.cpp
src/programs/mdrun/tests/rerun.cpp
src/programs/view/dialogs.cpp
src/programs/view/manager.cpp
src/programs/view/nmol.cpp
src/testutils/CMakeLists.txt
src/testutils/TestMacros.cmake
src/testutils/cmdlinetest.cpp
src/testutils/interactivetest.cpp
src/testutils/mpitest.cpp [new file with mode: 0644]
src/testutils/mpitest.h [new file with mode: 0644]
src/testutils/refdata-checkers.h
src/testutils/refdata-impl.h
src/testutils/refdata.cpp
src/testutils/refdata.h
src/testutils/testasserts.cpp
src/testutils/testasserts.h
src/testutils/testfileredirector.cpp
src/testutils/testinit.cpp
src/testutils/tests/CMakeLists.txt
src/testutils/tests/interactivetest.cpp
src/testutils/tests/mpitest.cpp [moved from src/gromacs/mdtypes/energyhistory.cpp with 61% similarity]
src/testutils/tests/refdata_tests.cpp
src/testutils/tests/xvgtest_tests.cpp
src/testutils/xvgtest.cpp
tests/CMakeLists.txt
tests/CheckTarget.cmake [new file with mode: 0644]
tests/CppCheck.cmake

index 80c5ab8afcb8d856f2bd722764e458f4601b2eb6..c76572b9b2a8c4a6982575a67e9b53ca5691dc5d 100644 (file)
 # To help us fund GROMACS development, we humbly ask that you cite
 # the research papers on the package. Check out http://www.gromacs.org.
 
-cmake_minimum_required(VERSION 2.8.8)
-# When we require cmake >= 2.8.12, it will provide
-# CMAKE_MINIMUM_REQUIRED_VERSION automatically, but in the meantime we
-# need to set a variable, and it must have a different name.
-set(GMX_CMAKE_MINIMUM_REQUIRED_VERSION "2.8.8")
+cmake_minimum_required(VERSION 3.4.3)
 
 # CMake modules/macros are in a subdirectory to keep this file cleaner
 # This needs to be set before project() in order to pick up toolchain files
@@ -70,11 +66,10 @@ include(gmxBuildTypeMSAN)
 include(gmxBuildTypeReleaseWithAssert)
 
 if(NOT CMAKE_BUILD_TYPE)
-    set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel Reference RelWithAssert Profile." FORCE)
-    # There's no need to offer a user the choice of ThreadSanitizer
+    set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel Reference RelWithAssert Profile TSAN ASAN MSAN." FORCE)
     # Set the possible values of build type for cmake-gui
     set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
-        "MinSizeRel" "RelWithDebInfo" "Reference" "RelWithAssert" "Profile")
+        "MinSizeRel" "RelWithDebInfo" "Reference" "RelWithAssert" "Profile" "TSAN" "ASAN" "MSAN")
 endif()
 if(CMAKE_CONFIGURATION_TYPES)
     # Add appropriate GROMACS-specific build types for the Visual
@@ -90,14 +85,8 @@ set(build_types_with_explicit_flags RELEASE DEBUG RELWITHDEBINFO RELWITHASSERT M
 
 set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS ON)
 
-# Set a default valgrind suppression file.
-# This unfortunately needs to duplicate information from CTest to work as
-# expected...
-set(MEMORYCHECK_SUPPRESSIONS_FILE
-    "${CMAKE_SOURCE_DIR}/cmake/legacy_and_external.supp"
-    CACHE FILEPATH
-    "File that contains suppressions for the memory checker")
-include(CTest)
+include(gmxCTestUtilities)
+gmx_ctest_init()
 
 include(gmxCPackUtilities)
 gmx_cpack_init()
@@ -197,12 +186,16 @@ gmx_add_cache_dependency(GMX_COOL_QUOTES BOOL "NOT GMX_FAHCORE" OFF)
 
 option(GMX_USE_OPENCL "Enable OpenCL acceleration" OFF)
 
-# Decide on GPU settings based on user-settings and GPU/CUDA detection.
-# GCC 4.6 requires CUDA 5.0 and VS2015 requires CUDA 8.0
+# Decide on GPU settings based on user-settings and GPU/CUDA
+# detection.  GCC 4.8 requires CUDA 6.0 (but we choose 6.5 for the
+# preliminary C++11 support), icc 15 requires CUDA 7.0, and VS2015
+# requires CUDA 8.0
 if(MSVC)
     set(REQUIRED_CUDA_VERSION 8.0)
+elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel")
+    set(REQUIRED_CUDA_VERSION 7.0)
 else()
-    set(REQUIRED_CUDA_VERSION 5.0)
+    set(REQUIRED_CUDA_VERSION 6.5)
 endif()
 set(REQUIRED_CUDA_COMPUTE_CAPABILITY 2.0)
 
@@ -328,6 +321,15 @@ include(gmxManageOpenMP)
 include(gmxCFlags)
 gmx_c_flags()
 
+# These collect libraries that Gromacs requires for linking:
+#  - Libraries that are required for libgromacs (only)
+set(GMX_EXTRA_LIBRARIES "")
+#  - Libraries that are required for all code in the repository
+set(GMX_COMMON_LIBRARIES "")
+#  - Libraries that all code linked against libgromacs needs
+#    (i.e., something that is exposed in installed headers).
+set(GMX_PUBLIC_LIBRARIES "")
+
 # This variable should be used for additional compiler flags which are not
 # generated in gmxCFlags nor are SIMD or MPI related.
 set(EXTRA_C_FLAGS "")
@@ -336,17 +338,6 @@ set(EXTRA_CXX_FLAGS "")
 # Run through a number of tests for buggy compilers and other issues
 include(gmxTestCompilerProblems)
 gmx_test_compiler_problems()
-# GMX_SIMD will not be set automatically until the second
-# pass (which is not strictly guaranteed to occur), so putting this
-# check here among logically-related tests is inefficient, but the
-# potential loss is likely zero.
-if(GMX_SIMD STREQUAL "AVX_256"
-        AND CMAKE_COMPILER_IS_GNUCC
-        AND (C_COMPILER_VERSION VERSION_EQUAL "4.6.1"
-            OR CXX_COMPILER_VERSION VERSION_EQUAL "4.6.1"))
-    message(FATAL_ERROR "gcc 4.6.1 has buggy support for AVX, and GROMACS mdrun will not work. If you want simulation performance, use a more recent compiler. Otherwise, use GMX_SIMD=SSE4.1")
-    # See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49002
-endif()
 
 # Implement double-precision option. This is complicated because we
 # need installed headers to use the precision mode of the build that
@@ -466,11 +457,6 @@ include(gmxManageSharedLibraries)
 # Find external packages                                               #
 ########################################################################
 
-# TNG wants zlib if it is available. And static libxml2 might have a dependency
-find_package(ZLIB QUIET)
-include(gmxTestZLib)
-gmx_test_zlib(HAVE_ZLIB)
-
 # Unconditionally find the package, as it is also required for unit
 # tests. This exports LIBXML2_FOUND, which we should not use because
 # it does not tell us that linking will succeed. Instead, we test that
@@ -516,7 +502,7 @@ endif()
 option(GMX_HWLOC "Add support for hwloc Portable Hardware locality library" ${GMX_HWLOC_DEFAULT})
 if(GMX_HWLOC)
     if(HWLOC_FOUND)
-        include_directories(${HWLOC_INCLUDE_DIRS})
+        include_directories(SYSTEM ${HWLOC_INCLUDE_DIRS})
         list(APPEND GMX_EXTRA_LIBRARIES ${HWLOC_LIBRARIES})
     else()
         message(FATAL_ERROR "Hwloc package support requested, but not found.")
@@ -575,7 +561,6 @@ if (TMPI_ATOMICS_DISABLED)
    add_definitions(-DTMPI_ATOMICS_DISABLED)
 endif()
 
-# Note this relies on zlib detection having already run
 include(gmxManageTNG)
 
 include(gmxManageLmfit)
@@ -583,8 +568,6 @@ include(gmxManageLmfit)
 if(GMX_GPU)
     # now that we have detected the dependencies, do the second configure pass
     gmx_gpu_setup()
-else()
-    mark_as_advanced(CUDA_HOST_COMPILER)
 endif()
 
 if(CYGWIN)
@@ -617,7 +600,9 @@ gmx_add_cache_dependency(GMX_BUILD_UNITTESTS BOOL BUILD_TESTING OFF)
 
 add_definitions( -DHAVE_CONFIG_H )
 include_directories(BEFORE ${CMAKE_SOURCE_DIR}/src)
-include_directories(BEFORE ${CMAKE_SOURCE_DIR}/src/external/thread_mpi/include)
+# TODO required at high level because both libgromacs and progs/mdrun
+# require it, both for thread-MPI and its atomics and mutexes.
+include_directories(BEFORE SYSTEM ${CMAKE_SOURCE_DIR}/src/external/thread_mpi/include)
 # Required for config.h, maybe should only be set in src/CMakeLists.txt
 include_directories(BEFORE ${CMAKE_BINARY_DIR}/src)
 
@@ -736,8 +721,8 @@ if(HAVE_TIME_H AND HAVE_UNISTD_H AND HAVE_CLOCK_GETTIME)
 endif()
 
 # Math and thread libraries must often come after all others when linking...
-if(HAVE_LIBM)
-    list(APPEND GMX_EXTRA_LIBRARIES m)
+if (HAVE_LIBM)
+    list(APPEND GMX_PUBLIC_LIBRARIES m)
 endif()
 
 option(GMX_NACL "Configure for Native Client builds" OFF)
@@ -787,7 +772,7 @@ else()
     message("CMAKE_CXX_FLAGS_RELEASE: ${GMXC_CXXFLAGS_RELEASE}")
     message("CMAKE_CXX_FLAGS_DEBUG: ${GMXC_CXXFLAGS_DEBUG}")
     message("CMAKE_EXE_LINKER_FLAGS: ${FFT_LINKER_FLAGS} ${MPI_LINKER_FLAGS}")
-    message("CMAKE_SHARED_LINKER_FLAGS: ${MPI_LINKER_FLAGS}")
+    message("CMAKE_SHARED_LINKER_FLAGS: ${FFT_LINKER_FLAGS} ${MPI_LINKER_FLAGS}")
 endif()
 
 if(NOT GMX_OPENMP)
@@ -837,17 +822,12 @@ include(gmxManageSuffixes)
 ################################################################
 # Shared library load path settings
 ################################################################
-# CMake supports RPATH on OS X only from 2.8.12 upwards.
-# CMAKE_SYSTEM_VERSION > 8.0 matches OS X 10.5 and above, where RPATH support
-# was added.
-
 if(NOT GMX_BUILD_SHARED_EXE)
     # No rpath
     set(CMAKE_SKIP_RPATH TRUE)
     set(CMAKE_EXE_LINK_DYNAMIC_C_FLAGS) # remove -Wl,-Bdynamic
     set(CMAKE_EXE_LINK_DYNAMIC_CXX_FLAGS)
-elseif((NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin") OR
-   ((CMAKE_SYSTEM_VERSION VERSION_GREATER 8.0) AND (NOT CMAKE_VERSION VERSION_LESS 2.8.12)))
+else()
     # The build folder always has bin/ and lib/; if we are also going to
     # install to lib/, then the installation RPATH works also in the build
     # tree.  This makes installation slightly faster (no need to rewrite the
@@ -857,23 +837,13 @@ elseif((NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin") OR
     endif()
     # Set the RPATH as relative to the executable location to make the
     # binaries relocatable.
-    if(NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+    if(NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin") #Assume OS X >=10.5
         set(CMAKE_INSTALL_RPATH "\$ORIGIN/../${GMX_LIB_INSTALL_DIR}")
     else()
         set(CMAKE_INSTALL_RPATH "@executable_path/../${GMX_LIB_INSTALL_DIR}")
     endif()
     set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
     set(CMAKE_MACOSX_RPATH 1)
-else()
-    # We are on Darwin/OSX, and CMake cannot handle RPATHs automatically.
-    if(CMAKE_SYSTEM_VERSION VERSION_GREATER 8.0)
-        # Set the RPATH options manually.
-        set(CMAKE_INSTALL_NAME_DIR "@rpath")
-        set(GMX_EXE_LINKER_FLAGS ${GMX_EXE_LINKER_FLAGS} "-Wl,-rpath,@executable_path/../${GMX_LIB_INSTALL_DIR}")
-    else()
-        # Use the old INSTALL_NAME_DIR mechanism if RPATH is not supported.
-        set(CMAKE_INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR}")
-    endif()
 endif()
 
 #COPYING file: Only necessary for binary distributions.
@@ -890,18 +860,7 @@ if (GMX_BUILD_FOR_COVERAGE)
 endif()
 
 if (BUILD_TESTING)
-    # "tests" target builds all the separate test binaries.
-    add_custom_target(tests)
-    # "run-ctest" is an internal target that actually runs the tests.
-    # This is necessary to be able to add separate targets that execute as part
-    # of 'make check', but are ensured to be executed after the actual tests.
-    add_custom_target(run-ctest
-                      COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
-                      COMMENT "Running all tests"
-                      VERBATIM)
-    add_dependencies(run-ctest tests)
-    # "check" target builds and runs all tests.
-    add_custom_target(check DEPENDS run-ctest)
+    include(tests/CheckTarget.cmake)
 endif()
 
 if (NOT GMX_BUILD_MDRUN_ONLY)
diff --git a/INSTALL-dev b/INSTALL-dev
new file mode 100644 (file)
index 0000000..b6e0836
--- /dev/null
@@ -0,0 +1,16 @@
+The GROMACS developers generally suggest you install GROMACS for
+production scientific use only from a tarball from an official
+source-code release.
+
+However, if you have a special need and wish to build and/or install a
+version from a git repository, please see
+docs/install-guide/index.rst in this repository, or (if applicable)
+the latest master branch documentation found via
+http://manual.gromacs.org/documentation/.
+
+Note for GROMACS developers
+---------------------------
+This file is excluded from the GROMACS source packages made with CPack,
+and not included into binary packages made with CPack. Source packages
+do include an INSTALL file containing the installation instructions, which
+has been compiled into plain text by Sphinx from docs/install-guide.
index 022aafdf96e028449852f2bf5dd72302c09d99f0..317f0aedce74bb4d3be9dd345114c0811e895c21 100644 (file)
@@ -34,7 +34,7 @@
 
 import os.path
 
-build_options = ['gcc-4.6']
+build_options = ['gcc-6.1', 'gcov-6.1']
 extra_projects = [Project.REGRESSIONTESTS]
 
 def do_build(context):
index 85711e98b1e86b6db5eabda9ffe616a4629daf10..d3cea58da8866684dcb30efd513fa6b0fb050002 100644 (file)
@@ -36,7 +36,7 @@ def do_build(context):
     # TODO: Make the XMLs go directly to the desired folder.
     # xml_dir = context.workspace.get_log_dir(category='cppcheck')
     cmake_opts = {
-            'CPPCHECK_EXECUTABLE': context.env.get_cppcheck_command(version='1.72'),
+            'CPPCHECK_EXECUTABLE': context.env.get_cppcheck_command(version='1.76.1'),
             'CPPCHECK_XML_OUTPUT': 'ON',
             'GMX_SIMD': 'Reference'
         }
index 2ef5be3327c11c47111e9a47649a16fa6a85996a..659d0b61283d02ba42e670f29de1c0710eccd481 100644 (file)
@@ -110,6 +110,12 @@ def do_build(context):
     if context.opts.x11:
         cmake_opts['GMX_X11'] = 'ON'
 
+    # At least hwloc on Jenkins produces a massive amount of reports about
+    # memory leaks, which cannot be reasonably suppressed because ASAN cannot
+    # produce a reasonable stack trace for them.
+    if context.opts.asan:
+        cmake_opts['GMX_HWLOC'] = 'OFF'
+
     regressiontests_path = context.workspace.get_project_dir(Project.REGRESSIONTESTS)
 
     if context.job_type == JobType.RELEASE:
@@ -153,7 +159,7 @@ def do_build(context):
     else:
         context.build_target(target='tests', keep_going=True)
 
-        context.run_ctest(args=['--output-on-failure'])
+        context.run_ctest(args=['--output-on-failure'], memcheck=context.opts.asan)
 
         context.build_target(target='install')
         # TODO: Consider what could be tested about the installed binaries.
@@ -165,8 +171,6 @@ def do_build(context):
             use_tmpi = not context.opts.mpi and context.opts.thread_mpi is not False
 
             cmd = 'perl gmxtest.pl -mpirun mpirun -xml -nosuffix all'
-            if context.opts.asan:
-                cmd+=' -parse asan_symbolize.py'
 
             # setting this stuff below is just a temporary solution,
             # it should all be passed as a proper the runconf from outside
@@ -193,4 +197,6 @@ def do_build(context):
                 cmd += ' -nt 2'
             if context.opts.double:
                 cmd += ' -double'
+            if context.opts.asan:
+                context.env.set_env_var('ASAN_OPTIONS', 'detect_leaks=0')
             context.run_cmd(cmd, shell=True, failure_message='Regression tests failed to execute')
index 6f24dcad9a562e4badc3abb453b81b3ad5316a0b..68f051ce69d279c41c455309e884674801ebc025 100644 (file)
@@ -1,13 +1,14 @@
-gcc-4.6 gpu cuda-5.0 mpi openmp x11 cmake-2.8.8
-gcc-4.8 gpu cuda-7.5 openmp release
+gcc-4.8 gpu cuda-6.5 mpi openmp x11
+gcc-4.8 gpu cuda-8.0 openmp release
 gcc-4.9 tsan fftpack simd=avx2_256
 gcc-6.1 double
-clang-3.4 double no-openmp fftpack asan
+clang-3.4 double no-openmp fftpack
+clang-3.8 no-openmp asan cmake-3.4.3
 # TODO move mdrun-only config to post-submit matrix
-clang-3.7 double mpi no-openmp fftpack mdrun-only
+clang-3.7 double mpi no-openmp fftpack mdrun-only cmake-3.4.3
 msvc-2015 openmp release
 icc-16.0 msvc-2015 fftpack
-icc-16.0 no-thread-mpi openmp mkl cmake-3.3.2 simd=avx_256
-gcc-5.2 mpi openmp simd=avx_128_fma
-gcc-4.8 openmp opencl cuda-7.5 mpi release
-gcc-5.2 openmp opencl amdappsdk-3.0
+icc-16.0 no-thread-mpi openmp mkl simd=avx_256
+gcc-5.1 mpi openmp cmake-3.4.3
+gcc-4.8 openmp opencl cuda-8.0 mpi release
+gcc-5.2 openmp opencl simd=avx_128_fma amdappsdk-3.0
index 2ee6d955aab90b550345583ac8b2a1f273ce1805..7786d17274820563ba2a79e87b78ce44e8eae820 100644 (file)
@@ -34,8 +34,7 @@
 
 import os.path
 
-# TODO when merging this to master, update gcc to 4.8
-build_options = ['gcc-4.7', 'cmake-3.4.3']
+build_options = ['gcc-4.8', 'cmake-3.4.3']
 extra_projects = [Project.REGRESSIONTESTS]
 
 def run_build(context, cmake_opts):
index ef5faea09b18ebad1480c5e220fb4bfd4f76ce11..36e4df93ad61b8a83150c1ebc80c1a9b95a0a052 100644 (file)
@@ -1,6 +1,6 @@
 # These configurations will be used to build and test the tarballs
 # before the release.
 gcc-4.8 mpi mdrun-only
-gcc-4.6 static
-gcc-4.7 double
+gcc-6.1 static
+gcc-5.1 double
 clang-3.4 static double
diff --git a/cmake/TestAVXMaskload.c b/cmake/TestAVXMaskload.c
deleted file mode 100644 (file)
index e8438a1..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#include<immintrin.h>
-int main()
-{
-    __m256d a;
-    __m256i mask;
-    double  d[4]={1,2,3,4};
-
-    a = _mm256_setzero_pd();
-    mask = _mm256_castpd_si256(a);
-
-#if GMX_SIMD_X86_AVX_GCC_MASKLOAD_BUG
-    a = _mm256_maskload_pd(d,_mm256_castsi256_pd(mask));
-#else
-    a = _mm256_maskload_pd(d,mask);
-#endif
-    return 0;
-}
-
diff --git a/cmake/TestClangVersion.c b/cmake/TestClangVersion.c
deleted file mode 100644 (file)
index f47c777..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-int main()
-{
-/* This detects 3.0 versions for both C and C++ clang. It detects the
- * version of the LLVM back end, and not (for example) the Apple clang
- * version number (which might be 4.1 or some number based on its
- * "compatibility with gcc 4.2.1," even though the LLVM back end is
- * 3.0!).
- *
- * If/when we have time or user complaints, we can maybe ban earlier
- * versions of clang, but we don't actually know there's a problem
- * with them at the time of this commit.
- */
-#if (__clang_major__ == 3) && (__clang_minor__ == 0)
-    return 0;
-#else
-#error clang version information not found
-#endif
-}
index a37fc309af041b76fb24627ccf108a56dd2fc7f7..505b1ef0a338729fadaea4bafeb7872c5c368dff 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2014, by the GROMACS development team, led by
+# Copyright (c) 2014,2016, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -42,9 +42,3 @@ foreach(_language C CXX)
     set(CMAKE_${_language}_FLAGS_ASAN ${_flags} CACHE STRING "${_human_readable_language} flags for address sanitizer")
     mark_as_advanced(CMAKE_${_language}_FLAGS_ASAN)
 endforeach()
-
-string(TOUPPER "${CMAKE_BUILD_TYPE}" _cmake_build_type)
-if (APPLE AND _cmake_build_type STREQUAL ASAN) #https://code.google.com/p/address-sanitizer/issues/detail?id=210
-   set(BUILD_SHARED_LIBS OFF CACHE BOOL "Disabled for ASAN builds" FORCE)
-endif()
-
index 6c33a5fe99d96de2d849085162d85b500bbb7ee6..8116ac7b7f44cafb4b12764ffee92ec2ef5eafe9 100644 (file)
@@ -48,8 +48,8 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "Reference")
     set(GMX_SOFTWARE_INVSQRT OFF CACHE BOOL "Disabled for regressiontests reference builds" FORCE)
     set(GMX_THREAD_MPI OFF CACHE BOOL "Disabled for regressiontests reference builds" FORCE)
 
-    if(NOT "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR NOT "${CMAKE_C_COMPILER_VERSION}" MATCHES "4.7")
+    if(NOT "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR NOT "${CMAKE_C_COMPILER_VERSION}" MATCHES "4.8")
         message(WARNING "Reference values for regressiontests should use GROMACS compiled with "
-            "gcc 4.7, but your configuration is using ${CMAKE_C_COMPILER_ID}-${CMAKE_C_COMPILER_VERSION}.")
+            "gcc 4.8, but your configuration is using ${CMAKE_C_COMPILER_ID}-${CMAKE_C_COMPILER_VERSION}.")
     endif()
 endif()
index 69bc7956f2da4d209dd5b3340853c258340cff6e..6210a2e04fe4828e6eb950ed11b7c60325d2a64c 100644 (file)
@@ -134,7 +134,11 @@ macro (gmx_c_flags)
             # Problematic with CUDA
             # GMX_TEST_CXXFLAG(CXXFLAGS_WARN_EFFCXX "-Wnon-virtual-dtor" GMXC_CXXFLAGS)
             GMX_TEST_CXXFLAG(CXXFLAGS_WARN_EXTRA "-Wextra -Wno-missing-field-initializers -Wpointer-arith" GMXC_CXXFLAGS)
-            GMX_TEST_CXXFLAG(CXXFLAGS_WARN_UNDEF "-Wundef" GMXC_CXXFLAGS)
+            # CUDA versions prior to 7.5 come with a header (math_functions.h) which uses the _MSC_VER macro
+            # unconditionally, so we don't use -Wundef for earlier CUDA versions.
+            if(NOT(GMX_GPU AND CUDA_VERSION VERSION_LESS "7.5"))
+                GMX_TEST_CXXFLAG(CXXFLAGS_WARN_UNDEF "-Wundef" GMXC_CXXFLAGS)
+            endif()
             GMX_TEST_CFLAG(CXXFLAGS_WARN_REL "-Wno-array-bounds" GMXC_CXXFLAGS_RELEASE_ONLY)
         endif()
         # new in gcc 4.5
@@ -148,28 +152,13 @@ macro (gmx_c_flags)
     if (CMAKE_C_COMPILER_ID MATCHES "Intel")
         if (NOT WIN32)
             if(NOT GMX_OPENMP)
-                if(CMAKE_C_COMPILER_VERSION VERSION_GREATER 13.99.99)
 # 3180: unrecognized OpenMP #pragma
-                    GMX_TEST_CFLAG(CFLAGS_PRAGMA "-wd3180" GMXC_CFLAGS)
-                else()
-# 161: unrecognized #pragma
-                    GMX_TEST_CFLAG(CFLAGS_PRAGMA "-wd161" GMXC_CFLAGS)
-                endif()
+                GMX_TEST_CFLAG(CFLAGS_PRAGMA "-wd3180" GMXC_CFLAGS)
             endif()
             if (GMX_COMPILER_WARNINGS)
-                if(CMAKE_C_COMPILER_VERSION VERSION_LESS 15.00.00)
-# 193: zero used for undefined preprocessing identifier ".."
-                    GMX_TEST_CFLAG(CFLAGS_WARN_OLD -wd193 GMXC_CFLAGS)
-                endif()
 # 177: function/variable ".." was declared but never referenced
-# 271: trailing comma is nonstandard
-# 304: access control not specified ("public" by default)
-# 383: value copied to temporary, reference to temporary used
-# 424: extra ";" ignored
-# 444: destructor for base class ".." is not virtual
-# 522: function ".." redeclared "inline" after being called
+# 411: class defines no constructor to initialize the following (incorrect for struct, initializer list works)
 # 593: variable ".." was set but never used
-# 869: parameter ".." was never referenced
 # 981: operands are evaluated in unspecified order
 #1418: external function definition with no prior declaration
 #1419: external declaration in primary source file
@@ -180,28 +169,20 @@ macro (gmx_c_flags)
 #2547: ".." was specified as both a system and non-system include directory
 #2557: comparison between signed and unsigned operands
 #3280: declaration hides member ".."
-#3346: dynamic exception specifications are deprecated
 #11074: Inlining inhibited by limit max-size(/max-total-size)
 #11076: To get full report use -opt-report=3 -opt-report-phase ipo (shown for previous remark)
-                GMX_TEST_CFLAG(CFLAGS_WARN "-w3 -wd177 -wd271 -wd304 -wd383 -wd424 -wd444 -wd522 -wd593 -wd869 -wd981 -wd1418 -wd1419 -wd1572 -wd1599 -wd2259 -wd2415 -wd2547 -wd2557 -wd3280 -wd3346 -wd11074 -wd11076" GMXC_CFLAGS)
+                GMX_TEST_CFLAG(CFLAGS_WARN "-w3 -wd177 -wd411 -wd593 -wd981 -wd1418 -wd1419 -wd1572 -wd1599 -wd2259 -wd2415 -wd2547 -wd2557 -wd3280 -wd11074 -wd11076" GMXC_CFLAGS)
             endif()
             GMX_TEST_CFLAG(CFLAGS_STDGNU "-std=gnu99" GMXC_CFLAGS)
-            GMX_TEST_CFLAG(CFLAGS_OPT "-ip -funroll-all-loops -alias-const -ansi-alias" GMXC_CFLAGS_RELEASE)
+            GMX_TEST_CFLAG(CFLAGS_OPT "-ip -funroll-all-loops -alias-const -ansi-alias -no-prec-div -fimf-domain-exclusion=14 -static-intel" GMXC_CFLAGS_RELEASE)
             GMX_TEST_CFLAG(CFLAGS_DEBUG "-O0" GMXC_CFLAGS_DEBUG) #icc defaults to -O2 even with -g
             GMX_TEST_CFLAG(CFLAGS_FP_RELASSERT "-fp-model except -fp-model precise" GMXC_CFLAGS_RELWITHASSERT)
         else()
             if(NOT GMX_OPENMP)
-                if(CMAKE_C_COMPILER_VERSION VERSION_GREATER 13.99.99)
-                    GMX_TEST_CFLAG(CFLAGS_PRAGMA "/wd3180" GMXC_CFLAGS)
-                else()
-                    GMX_TEST_CFLAG(CFLAGS_PRAGMA "/wd161" GMXC_CFLAGS)
-                endif()
+                GMX_TEST_CFLAG(CFLAGS_PRAGMA "/wd3180" GMXC_CFLAGS)
             endif()
             if (GMX_COMPILER_WARNINGS)
-                if(CMAKE_C_COMPILER_VERSION VERSION_LESS 15.00.00)
-                    GMX_TEST_CFLAG(CFLAGS_WARN_OLD /wd193 GMXC_CFLAGS)
-                endif()
-                GMX_TEST_CFLAG(CFLAGS_WARN "/W3 /wd177 /wd271 /wd304 /wd383 /wd424 /wd444 /wd522 /wd593 /wd869 /wd981 /wd1418 /wd1419 /wd1572 /wd1599 /wd2259 /wd2415 /wd2547 /wd2557 /wd3280 /wd3346" GMXC_CFLAGS)
+GMX_TEST_CFLAG(CFLAGS_WARN "/W3 /wd177 /wd411 /wd593 /wd981 /wd1418 /wd1419 /wd1572 /wd1599 /wd2259 /wd2415 /wd2547 /wd2557 /wd3280" GMXC_CFLAGS)
             endif()
             GMX_TEST_CFLAG(CFLAGS_OPT "/Qip" GMXC_CFLAGS_RELEASE)
         endif()
@@ -210,37 +191,34 @@ macro (gmx_c_flags)
     if (CMAKE_CXX_COMPILER_ID MATCHES "Intel")
         if (NOT WIN32) 
             if(NOT GMX_OPENMP)
-                if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 13.99.99)
-                    GMX_TEST_CXXFLAG(CXXFLAGS_PRAGMA "-wd3180" GMXC_CXXFLAGS)
-                else()
-                    GMX_TEST_CXXFLAG(CXXFLAGS_PRAGMA "-wd161" GMXC_CXXFLAGS)
-                endif()
+                GMX_TEST_CXXFLAG(CXXFLAGS_PRAGMA "-wd3180" GMXC_CXXFLAGS)
             endif()
             if (GMX_COMPILER_WARNINGS)
-                if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.00.00)
-                    GMX_TEST_CXXFLAG(CXXFLAGS_WARN_OLD -wd193 GMXC_CXXFLAGS)
+                if (GMX_GPU)
+# Suppress warnings from CUDA headers
+# 7:   unrecognized token
+# 82:  storage class is not first
+# The below are also required for math_functions.h / math_functions.hpp at least until CUDA 8.0-RC
+# 193: zero used for undefined preprocessing identifer
+# 3346:dynamic exception specifiers are deprecated
+                    GMX_TEST_CXXFLAG(CXXFLAGS_WARN_OLD_GPU "-wd7 -wd82 -wd193 -wd3346" GMXC_CXXFLAGS)
                 endif()
 #All but the following warnings are identical for the C-compiler (see above)
-#1782: #pragma once is obsolete
+# 383: value copied to temporary, reference to temporary used
+# 444: destructor for base class ".." is not virtual
 #2282: unrecognized GCC pragma
-                GMX_TEST_CXXFLAG(CXXFLAGS_WARN "-w3 -wd177 -wd271 -wd304 -wd383 -wd424 -wd444 -wd522 -wd593 -wd869 -wd981 -wd1418 -wd1419 -wd1572 -wd1599 -wd2259 -wd2415 -wd2547 -wd2557 -wd3280 -wd3346 -wd11074 -wd11076 -wd1782 -wd2282" GMXC_CXXFLAGS)
+                GMX_TEST_CXXFLAG(CXXFLAGS_WARN "-w3 -wd177 -wd383 -wd411 -wd444 -wd981 -wd1418 -wd1572 -wd1599 -wd2259 -wd3280 -wd11074 -wd11076 -wd2282" GMXC_CXXFLAGS)
             endif()
-            GMX_TEST_CXXFLAG(CXXFLAGS_OPT "-ip -funroll-all-loops -alias-const -ansi-alias" GMXC_CXXFLAGS_RELEASE)
+            GMX_TEST_CXXFLAG(CXXFLAGS_OPT "-ip -funroll-all-loops -alias-const -ansi-alias -no-prec-div -fimf-domain-exclusion=14 -static-intel" GMXC_CXXFLAGS_RELEASE)
             GMX_TEST_CXXFLAG(CXXFLAGS_DEBUG "-O0" GMXC_CXXFLAGS_DEBUG)
             GMX_TEST_CXXFLAG(CXXFLAGS_FP_RELASSERT "-fp-model except -fp-model precise" GMXC_CXXFLAGS_RELWITHASSERT)
         else()
+#809: exception specification for virtual function X is incompatible with that of overridden function
             if(NOT GMX_OPENMP)
-                if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 13.99.99)
-                    GMX_TEST_CXXFLAG(CXXFLAGS_PRAGMA "/wd3180" GMXC_CFLAGS)
-                else()
-                    GMX_TEST_CXXFLAG(CXXFLAGS_PRAGMA "/wd161" GMXC_CXXFLAGS)
-                endif()
+                GMX_TEST_CXXFLAG(CXXFLAGS_PRAGMA "/wd3180" GMXC_CFLAGS)
             endif()
             if (GMX_COMPILER_WARNINGS)
-                if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.00.00)
-                    GMX_TEST_CXXFLAG(CXXFLAGS_WARN_OLD /wd193 GMXC_CXXFLAGS)
-                endif()
-                GMX_TEST_CXXFLAG(CXXFLAGS_WARN "/W3 /wd177 /wd271 /wd304 /wd383 /wd424 /wd444 /wd522 /wd593 /wd869 /wd981 /wd1418 /wd1419 /wd1572 /wd1599 /wd2259 /wd2415 /wd2547 /wd2557 /wd3280 /wd3346 /wd1782 /wd2282" GMXC_CXXFLAGS)
+GMX_TEST_CXXFLAG(CXXFLAGS_WARN "/W3 /wd177 /wd383 /wd411 /wd444 /wd809 /wd981 /wd1418 /wd1572 /wd1599 /wd2259 /wd3280 /wd11074 /wd11076 /wd2282" GMXC_CXXFLAGS)
             endif()
             GMX_TEST_CXXFLAG(CXXFLAGS_OPT "/Qip" GMXC_CXXFLAGS_RELEASE)
         endif()
index 5e80714cd9d25ff5f21cd9bc222a42efc86e32d5..7867998a8a68c61587fbbc023adfee54e7baa9a4 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2014,2015, by the GROMACS development team, led by
+# Copyright (c) 2014,2015,2016, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -119,7 +119,7 @@ function (gmx_cpack_write_config)
     set(CPACK_SOURCE_GENERATOR TGZ)
     set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
     set(CPACK_SOURCE_IGNORE_FILES
-        "\\\\.isreposource$;\\\\.git/;\\\\.gitignore$;\\\\.gitattributes;")
+        "\\\\.isreposource$;\\\\.git/;\\\\.gitignore$;\\\\.gitattributes;INSTALL-dev;")
     # Get the list of directories added with gmx_cpack_add_generated_source_directory()
     get_property(CPACK_SOURCE_INSTALLED_DIRECTORIES
         GLOBAL PROPERTY GMX_CPACK_SOURCE_INSTALLED_DIRECTORIES)
diff --git a/cmake/gmxCTestUtilities.cmake b/cmake/gmxCTestUtilities.cmake
new file mode 100644 (file)
index 0000000..89715f9
--- /dev/null
@@ -0,0 +1,75 @@
+#
+# This file is part of the GROMACS molecular simulation package.
+#
+# Copyright (c) 2016, by the GROMACS development team, led by
+# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+# and including many others, as listed in the AUTHORS file in the
+# top-level source directory and at http://www.gromacs.org.
+#
+# GROMACS is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1
+# of the License, or (at your option) any later version.
+#
+# GROMACS is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with GROMACS; if not, see
+# http://www.gnu.org/licenses, or write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+#
+# If you want to redistribute modifications to GROMACS, please
+# consider that scientific software is very special. Version
+# control is crucial - bugs must be traceable. We will be happy to
+# consider code for inclusion in the official distribution, but
+# derived work must not be called official GROMACS. Details are found
+# in the README & COPYING files - if they are missing, get the
+# official version at http://www.gromacs.org.
+#
+# To help us fund GROMACS development, we humbly ask that you cite
+# the research papers on the package. Check out http://www.gromacs.org.
+
+# Helper macros to encapsulate some usage of CTest
+#
+# This file is intended to contain CTest workarounds and such.
+include(CMakeParseArguments)
+
+macro (gmx_ctest_init)
+    # Set a default valgrind suppression file.
+    # This unfortunately needs to duplicate information from CTest to work as
+    # expected...
+    #set(MEMORYCHECK_SUPPRESSIONS_FILE
+    #    "${CMAKE_SOURCE_DIR}/cmake/legacy_and_external.supp"
+    #    CACHE FILEPATH
+    #    "File that contains suppressions for the memory checker")
+    string(TOUPPER "${CMAKE_BUILD_TYPE}" _cmake_build_type)
+    if (_cmake_build_type STREQUAL "ASAN")
+        set(MEMORYCHECK_TYPE "AddressSanitizer")
+    endif()
+    include(CTest)
+    # At least with CMake 3.4.1 on OS X, AddressSanitizer support in CTest
+    # does not work without this...
+    set(_ctest_config_file "${PROJECT_BINARY_DIR}/DartConfiguration.tcl")
+    file(STRINGS ${_ctest_config_file} _existing REGEX "^CMakeCommand: ")
+    if (NOT _existing)
+        file(APPEND ${_ctest_config_file} "\nCMakeCommand: ${CMAKE_COMMAND}\n")
+    endif()
+endmacro()
+
+function (gmx_get_test_prefix_cmd VAR)
+    set(_options IGNORE_LEAKS)
+    cmake_parse_arguments(ARG "${_options}" "" "" ${ARGN})
+    set(_opts "")
+    if (ARG_IGNORE_LEAKS OR APPLE)
+        list(APPEND _opts "detect_leaks=0")
+    endif()
+    set(_cmd "")
+    if (MEMORYCHECK_TYPE STREQUAL "AddressSanitizer")
+        string(REPLACE ";" " " _opts "${_opts}")
+        set(_cmd ${PROJECT_SOURCE_DIR}/cmake/with_asan_opts.sh ${_opts} --)
+    endif()
+    set(${VAR} "${_cmd}" PARENT_SCOPE)
+endfunction()
index ae3279a8317d9e5a9d8048d0356adde3589fd2b4..082c3eec80d300f0c45f142b89779801b6129e3c 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2014, by the GROMACS development team, led by
+# Copyright (c) 2014,2016, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -90,10 +90,6 @@ endfunction()
 
 # More flexible alternative to add_custom_command() and add_custom_target()
 # for dependent custom commands.  It adds a few convenience features:
-#   - Support for custom commands that always run (like add_custom_target()),
-#     but still have the ability to act as dependencies of other custom
-#     commands (such that the dependent commands run only if the output
-#     has been updated) also for Ninja.
 #   - Adds file-level dependencies between custom targets added with this
 #     command such that if there is a target-level dependency, it also implies
 #     that the custom command should always be run if the output file of the
@@ -110,16 +106,13 @@ endfunction()
 #                                [WORKING_DIRECTORY <dir>]
 #                                [DEPENDS <deps...>]
 #                                [DEPENDS_FILE_LIST <list>]
-#                                [COMMENT <comment>])
+#                                [COMMENT <comment>] [USES_TERMINAL])
 #
 #   <target>
 #     - Name of the custom target to create.
 #   RUN_ALWAYS
-#     - Create the command such that it always runs.
-#       This takes care of differences between the Ninja generator and others,
-#       which require different rules to make this happen such that
-#       dependencies on the output of the target work correctly, also in the
-#       case the command does not always update the timestamp of the output.
+#     - Create the command such that it always runs, and may update the output
+#       file in the process.
 #       The dependencies listed with DEPENDS are ignored in this case.
 #   ADD_FAST_TARGET
 #     - In addition to creating <target>, create a secondary target
@@ -143,6 +136,8 @@ endfunction()
 #     - Passed to add_custom_command()/add_custom_target()
 #   COMMENT
 #     - Passed to add_custom_command()/add_custom_target()
+#   USES_TERMINAL
+#     - Passed to add_custom_command()/add_custom_target()
 #   DEPENDS
 #     - Dependencies passed to add_custom_command().  Any targets in this list
 #       that have been created with gmx_add_custom_output_target() are
@@ -176,7 +171,7 @@ function (gmx_add_custom_output_target targetname)
             set(_add_fast ON)
         elseif ("x${_arg}" MATCHES "^x(OUTPUT|DEPENDS|DEPENDS_FILE_LIST)$")
             set(_option ${_arg})
-        elseif ("x${_arg}" MATCHES "^x(COMMAND|COMMENT|WORKING_DIRECTORY)$")
+        elseif ("x${_arg}" MATCHES "^x(COMMAND|COMMENT|WORKING_DIRECTORY|USES_TERMINAL)$")
             set(_option "PASS")
             list(APPEND _command_args "${_arg}")
         elseif ("x${_option}" STREQUAL "xDEPENDS")
@@ -214,37 +209,12 @@ function (gmx_add_custom_output_target targetname)
     endif()
     # Create the actual command as requested.
     if (NOT _always)
-        # If the command does not need to run always, the standard CMake
-        # mechanism is sufficient.
         add_custom_command(OUTPUT ${_output}
             ${_command_args} DEPENDS ${_deps} VERBATIM)
         add_custom_target(${targetname} DEPENDS ${_output})
-    elseif (CMAKE_GENERATOR STREQUAL "Ninja")
-        # Ninja requires all generated files mentioned in dependencies of custom
-        # commands to be actually mentioned in the build system, and luckily
-        # add_custom_command() makes that possible.
-        # But it seems impossible to create a robust custom command that would be
-        # always run, so other generators that do not have this constraint simply
-        # use an add_custom_target().
-        #
-        # The second, phony file is never created, so the rule is always
-        # triggered again.  TODO: Figure out why this works, even though ninja
-        # very eagerly complains about missing files.
-        # This unfortunately does not work with the make generator, as
-        # the non-existent second file causes some part of the generated system
-        # erase the first file at the beginning of every build, causing a full
-        # rebuild of the dependencies.
-        add_custom_command(OUTPUT ${_output} ${targetname}-phony
-            ${_command_args} VERBATIM)
-        # The generated Ninja build system would probably work fine even
-        # without this target, but CMake requires all custom commands to belong
-        # to a target in the same CMakeLists.txt to generate anything for them.
-        add_custom_target(${targetname} DEPENDS ${_output})
     else()
-        # For other generators, a target-level dependency on the custom target
-        # ensures that the output is created before the dependent targets'
-        # dependencies are even evaluated.
-        add_custom_target(${targetname} ${_command_args} VERBATIM)
+        add_custom_target(${targetname} BYPRODUCTS ${_output}
+            ${_command_args} VERBATIM)
     endif()
     # Store the output file name in a custom property to be used in dependency
     # resolution later.
index a6b5439303a32ea1a687c026bf262d6e7de91e0f..60a74291ecf64a174b7366d30efb143388c05b2a 100644 (file)
@@ -57,18 +57,8 @@ if ((GMX_GPU OR GMX_GPU_AUTO) AND NOT GMX_GPU_DETECTION_DONE)
     gmx_detect_gpu()
 endif()
 
-# CMake 3.0-3.1 has a bug in the following case, which breaks
-# configuration on at least BlueGene/Q. Fixed in 3.1.1
-if ((NOT CMAKE_VERSION VERSION_LESS "3.0.0") AND
-    (CMAKE_VERSION VERSION_LESS "3.1.1") AND
-        (CMAKE_CROSSCOMPILING AND NOT CMAKE_SYSTEM_PROCESSOR))
-    message(STATUS "Cannot search for CUDA because the CMake find package has a bug. Set a valid CMAKE_SYSTEM_PROCESSOR if you need to detect CUDA")
-else()
-    set(CAN_RUN_CUDA_FIND_PACKAGE 1)
-endif()
-
 # We need to call find_package even when we've already done the detection/setup
-if(GMX_GPU OR GMX_GPU_AUTO AND CAN_RUN_CUDA_FIND_PACKAGE)
+if(GMX_GPU OR GMX_GPU_AUTO)
     if(NOT GMX_GPU AND NOT GMX_DETECT_GPU_AVAILABLE)
         # Stay quiet when detection has occured and found no GPU.
         # Noise is acceptable when there is a GPU or the user required one.
@@ -82,23 +72,6 @@ if(GMX_GPU OR GMX_GPU_AUTO AND CAN_RUN_CUDA_FIND_PACKAGE)
     endif()
 
     find_package(CUDA ${REQUIRED_CUDA_VERSION} ${FIND_CUDA_QUIETLY})
-
-    # Cmake 2.8.12 (and CMake 3.0) introduced a new bug where the cuda
-    # library dir is added twice as an rpath on APPLE, which in turn causes
-    # the install_name_tool to wreck the binaries when it tries to remove this
-    # path. Since this is set inside the cuda module, we remove the extra rpath
-    # added in the library string - an rpath is not a library anyway, and at
-    # least for Gromacs this works on all CMake versions. This should be
-    # reasonably future-proof, since newer versions of CMake appear to handle
-    # the rpath automatically based on the provided library path, meaning
-    # the explicit rpath specification is no longer needed.
-    if(APPLE AND (CMAKE_VERSION VERSION_GREATER 2.8.11))
-        foreach(elem ${CUDA_LIBRARIES})
-            if(elem MATCHES "-Wl,.*")
-                list(REMOVE_ITEM CUDA_LIBRARIES ${elem})
-            endif()
-        endforeach(elem)
-    endif()
 endif()
 
 # Depending on the current vale of GMX_GPU and GMX_GPU_AUTO:
@@ -182,13 +155,13 @@ endif()
 # We need to mark these advanced outside the conditional, otherwise, if the
 # user turns GMX_GPU=OFF after a failed cmake pass, these variables will be
 # left behind in the cache.
-mark_as_advanced(CUDA_BUILD_CUBIN CUDA_BUILD_EMULATION CUDA_SDK_ROOT_DIR CUDA_VERBOSE_BUILD # cmake 2.8.9 still spews these, check again when requirements change
-                 CUDA_SEPARABLE_COMPILATION      # not present at least with cmake 3.2, remove when required
-                 CUDA_USE_STATIC_CUDA_RUNTIME    # since cmake 3.3
-                 CUDA_dl_LIBRARY CUDA_rt_LIBRARY # - || -
+mark_as_advanced(CUDA_SDK_ROOT_DIR
+                 CUDA_USE_STATIC_CUDA_RUNTIME
+                 CUDA_dl_LIBRARY CUDA_rt_LIBRARY
                  )
 if(NOT GMX_GPU)
     mark_as_advanced(CUDA_TOOLKIT_ROOT_DIR)
+    mark_as_advanced(CUDA_HOST_COMPILER)
 endif()
 
 # Try to execute ${CUDA_NVCC_EXECUTABLE} --version and set the output
index 8c8562b9c75dc100154a1679ee369d26dc821284..aeb7937c7405d06c7d3213dcff64df7c7fe83258 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2013,2014, by the GROMACS development team, led by
+# Copyright (c) 2013,2014,2016, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -89,7 +89,7 @@ macro(manage_linear_algebra_library name function_in_library)
             set(CMAKE_REQUIRED_FLAGS "${FFT_LINKER_FLAGS}")
             # This may also not work correctly if the user changes
             # MKL_LIBRARIES after the first run. However,
-            # MKL_LIBRARIES is only needed for icc version < 11, or
+            # MKL_LIBRARIES is only needed
             # for trying to use MKL with a non-Intel compiler, and we
             # can live with that for now.
             check_function_exists(${function_in_library} _${name}_mkl_works)
@@ -110,8 +110,7 @@ macro(manage_linear_algebra_library name function_in_library)
         if (NOT _library_was_found)
             set(${name}_FIND_QUIETLY ${_find_quietly})
             # Note that this finds all kinds of system libraries,
-            # including Apple's Accelerate Framework (and perhaps MKL for
-            # icc < 11).
+            # including Apple's Accelerate Framework
             find_package(${name})
             if (${name}_FOUND)
                 set(_libraries_to_link ${${name}_LIBRARIES})
index 1d3645a44383c704275d67fb88e3457b8f6ffd5a..02db55732d049d95d626ffc6700d524eee7ba7f5 100644 (file)
@@ -53,7 +53,7 @@ if(GMX_MPI)
         set(MPI_COMPILE_FLAGS ${MPI_C_COMPILE_FLAGS})
         set(MPI_LINKER_FLAGS ${MPI_C_LINK_FLAGS})
         include_directories(SYSTEM ${MPI_C_INCLUDE_PATH})
-        list(APPEND GMX_EXTRA_LIBRARIES ${MPI_C_LIBRARIES})
+        list(APPEND GMX_COMMON_LIBRARIES ${MPI_C_LIBRARIES})
       endif()
       set(MPI_FOUND ${MPI_C_FOUND})
   else()
@@ -165,15 +165,6 @@ if(GMX_MPI)
       endif()
     endif()
     unset(MPINAME_BIN CACHE)
-
-    # Using find_file() runs the CMake standard module
-    # GetPrerequisites.cmake, which adds the file_cmd
-    # variable to the top-level CMake namespace. This is
-    # fixed in CMake 2.8.10. Meanwhile, clean up for it.
-    if(CMAKE_VERSION VERSION_LESS "2.8.10")
-        mark_as_advanced(file_cmd)
-    endif()
-
   else()
       message(FATAL_ERROR
         "MPI support requested, but no MPI compiler found. Either set the "
index 34de4bad36cf1cacbe6c5e54b650770e1153412b..c8561f44febf6f6e004c7c838a56a0d0e54cf0b8 100644 (file)
@@ -36,7 +36,7 @@
 # pain as much as possible:
 # - use the CUDA_HOST_COMPILER if defined by the user, otherwise
 # - auto-detect compatible nvcc host compiler and set nvcc -ccbin (if not MPI wrapper)
-# - set icc compatibility mode to gcc 4.6
+# - set icc compatibility mode to gcc 4.8.1
 # - (advanced) variables set:
 #   * CUDA_HOST_COMPILER            - the host compiler for nvcc (only with cmake <2.8.10)
 #   * CUDA_HOST_COMPILER_OPTIONS    - the full host-compiler related option list passed to nvcc
@@ -87,25 +87,7 @@ endfunction()
 
 # set up host compiler and its options
 if(CUDA_HOST_COMPILER_CHANGED)
-    # FindCUDA in CMake 2.8.10 sets the host compiler internally
-    if (CMAKE_VERSION VERSION_LESS "2.8.10")
-        set(CUDA_HOST_COMPILER ${CUDA_HOST_COMPILER}
-            CACHE PATH "Host compiler for nvcc")
-    endif()
-
-    # On *nix force icc in gcc 4.6 compatibility mode. This is needed
-    # as even with icc used as host compiler, when icc's gcc compatibility
-    # mode is higher than the max gcc version officially supported by CUDA,
-    # nvcc will freak out.
     set(CUDA_HOST_COMPILER_OPTIONS "")
-    if (UNIX AND
-            ((CMAKE_C_COMPILER_ID MATCHES "Intel" AND
-              (CUDA_HOST_COMPILER_AUTOSET OR CMAKE_C_COMPILER STREQUAL CUDA_HOST_COMPILER)) OR
-            (CMAKE_CXX_COMPILER_ID MATCHES "Intel" AND CMAKE_CXX_COMPILER STREQUAL CUDA_HOST_COMPILER))
-        )
-        message(STATUS "Setting Intel Compiler compatibity mode to gcc 4.6 for nvcc host compilation")
-        list(APPEND CUDA_HOST_COMPILER_OPTIONS "-Xcompiler;-gcc-version=460")
-    endif()
 
     if(APPLE AND CMAKE_C_COMPILER_ID MATCHES "GNU")
         # Some versions of gcc-4.8 and gcc-4.9 produce errors (in particular on OS X)
@@ -191,52 +173,11 @@ list(APPEND GMX_CUDA_NVCC_FLAGS "${GMX_CUDA_NVCC_GENCODE_FLAGS}")
 list(APPEND GMX_CUDA_NVCC_FLAGS "-use_fast_math")
 
 # assemble the CUDA host compiler flags
-# with CMake <2.8.10 the host compiler needs to be set on the nvcc command line
-if (CMAKE_VERSION VERSION_LESS "2.8.10")
-    list(APPEND GMX_CUDA_NVCC_FLAGS "-ccbin=${CUDA_HOST_COMPILER}")
-endif()
 list(APPEND GMX_CUDA_NVCC_FLAGS "${CUDA_HOST_COMPILER_OPTIONS}")
 
 # The flags are set as local variables which shadow the cache variables. The cache variables
 # (can be set by the user) are appended. This is done in a macro to set the flags when all
 # host compiler flags are already set.
 macro(GMX_SET_CUDA_NVCC_FLAGS)
-    if(CUDA_PROPAGATE_HOST_FLAGS)
-        set(CUDA_PROPAGATE_HOST_FLAGS OFF)
-
-        # When CUDA 6.5 is required we should use C++11 also for CUDA and also propagate
-        # the C++11 flag to CUDA. Then we can use the solution implemented in FindCUDA
-        # (starting with 3.3 - can be backported). For now we need to remove the C++11
-        # flag which means we need to manually propagate all other flags.
-        string(REGEX REPLACE "[-]+std=c\\+\\+0x" "" _CMAKE_CXX_FLAGS_SANITIZED "${CMAKE_CXX_FLAGS}")
-
-        # The IBM xlc compiler chokes if we use both altivec and Cuda. Solve
-        # this by not propagating the flag in this case.
-        if(CMAKE_CXX_COMPILER_ID MATCHES "XL")
-            string(REGEX REPLACE "-qaltivec" "" _CMAKE_CXX_FLAGS_SANITIZED "${_CMAKE_CXX_FLAGS_SANITIZED}")
-        endif()
-
-        # CUDA versions prior to 7.5 come with a header (math_functions.h) which uses the _MSC_VER macro
-        # unconditionally, so we strip -Wundef from the propagatest flags for earlier CUDA versions.
-        if (CUDA_VERSION VERSION_LESS "7.5")
-            string(REGEX REPLACE "-Wundef" "" _CMAKE_CXX_FLAGS_SANITIZED "${_CMAKE_CXX_FLAGS_SANITIZED}")
-        endif()
-
-        string(REPLACE " " "," _flags "${_CMAKE_CXX_FLAGS_SANITIZED}")
-        set(CUDA_NVCC_FLAGS "${GMX_CUDA_NVCC_FLAGS};${CUDA_NVCC_FLAGS};-Xcompiler;${_flags}")
-
-        # Create list of all possible configurations. For multi-configuration this is CMAKE_CONFIGURATION_TYPES
-        # and for single configuration CMAKE_BUILD_TYPE. Not sure why to add the default ones, but FindCUDA
-        # claims one should.
-        set(CUDA_configuration_types ${CMAKE_CONFIGURATION_TYPES} ${CMAKE_BUILD_TYPE} Debug MinSizeRel Release RelWithDebInfo)
-        list(REMOVE_DUPLICATES CUDA_configuration_types)
-
-        foreach(_config ${CUDA_configuration_types})
-            string(TOUPPER ${_config} _config_upper)
-            string(REPLACE " " "," _flags "${CMAKE_CXX_FLAGS_${_config_upper}}")
-            set(CUDA_NVCC_FLAGS_${_config_upper} "${CUDA_NVCC_FLAGS_${_config_upper}};-Xcompiler;${_flags}")
-        endforeach()
-    else()
-        set(CUDA_NVCC_FLAGS "${GMX_CUDA_NVCC_FLAGS};${CUDA_NVCC_FLAGS}")
-    endif()
+    set(CUDA_NVCC_FLAGS "${GMX_CUDA_NVCC_FLAGS};${CUDA_NVCC_FLAGS}")
 endmacro()
index 5903957beff2a67a1d01d03e107a79e8bf0b202d..f1b373159e5149bc1fe4e2b2a48c56e370a0b2e8 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by
+# Copyright (c) 2012,2013,2014,2015,2016, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
 # and then does some additional tests for flags afterwards.
 
 if(GMX_OPENMP)
-    if(CMAKE_C_COMPILER_ID MATCHES "Cray" AND CMAKE_VERSION VERSION_LESS 3)
-        message(STATUS "OpenMP multithreading is not detected correctly for the Cray compiler with CMake before version 3.0 (see http://public.kitware.com/Bug/view.php?id=14567)")
-        set(GMX_OPENMP OFF CACHE BOOL
-            "OpenMP multithreading is not detected correctly for the Cray compiler with CMake before version 3.0 (see http://public.kitware.com/Bug/view.php?id=14567)" FORCE)
-    else()
-        # We should do OpenMP detection if we get here
-        # OpenMP check must come before other CFLAGS!
-        find_package(OpenMP)
-        if(OPENMP_FOUND)
-            # 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 MINGW))
-                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()
-                    # Only set a linker flag if the user didn't set them manually
-                    if(NOT DEFINED OpenMP_LINKER_FLAGS)
-                        set(OpenMP_LINKER_FLAGS "${OpenMP_C_FLAGS}")
-                    endif()
-                    if(NOT DEFINED OpenMP_SHARED_LINKER_FLAGS)
-                        set(OpenMP_SHARED_LINKER_FLAGS "${OpenMP_C_FLAGS}")
-                    endif()
+    # We should do OpenMP detection if we get here
+    # OpenMP check must come before other CFLAGS!
+    find_package(OpenMP)
+    if(OPENMP_FOUND)
+        # 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 MINGW))
+            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()
+                # Only set a linker flag if the user didn't set them manually
+                if(NOT DEFINED OpenMP_LINKER_FLAGS)
+                    set(OpenMP_LINKER_FLAGS "${OpenMP_C_FLAGS}")
+                endif()
+                if(NOT DEFINED OpenMP_SHARED_LINKER_FLAGS)
+                    set(OpenMP_SHARED_LINKER_FLAGS "${OpenMP_C_FLAGS}")
                 endif()
             endif()
-            if(MINGW)
-                #GCC Bug 48659
-                set(OpenMP_C_FLAGS "${OpenMP_C_FLAGS} -mstackrealign")
-            endif()
-        else()
-            message(WARNING
-                    "The compiler you are using does not support OpenMP parallelism. This might hurt your performance a lot, in particular with GPUs. Try using a more recent version, or a different compiler. For now, we are proceeding by turning off OpenMP.")
-            set(GMX_OPENMP OFF CACHE STRING "Whether GROMACS will use OpenMP parallelism." FORCE)
         endif()
+        if(MINGW)
+            #GCC Bug 48659
+            set(OpenMP_C_FLAGS "${OpenMP_C_FLAGS} -mstackrealign")
+        endif()
+    else()
+        message(WARNING
+                "The compiler you are using does not support OpenMP parallelism. This might hurt your performance a lot, in particular with GPUs. Try using a more recent version, or a different compiler. For now, we are proceeding by turning off OpenMP.")
+        set(GMX_OPENMP OFF CACHE STRING "Whether GROMACS will use OpenMP parallelism." FORCE)
     endif()
 endif()
 gmx_dependent_cache_variable(GMX_OPENMP_MAX_THREADS
index f3bf27bde9c7f11d3ed6866a954d7ec9ba591b47..b862a71cd61344571c3dc699903248cc19164bb6 100644 (file)
@@ -32,8 +32,6 @@
 # To help us fund GROMACS development, we humbly ask that you cite
 # the research papers on the package. Check out http://www.gromacs.org.
 
-# include avx test source, used if the AVX flags are set below
-include(gmxTestAVXMaskload)
 include(gmxFindFlagsForSource)
 
 # Macro that manages setting the respective C and C++ toolchain
@@ -247,8 +245,6 @@ elseif(GMX_SIMD STREQUAL "AVX_128_FMA")
     set(GMX_SIMD_X86_${GMX_SIMD} 1)
     set(SIMD_STATUS_MESSAGE "Enabling 128-bit AVX SIMD GROMACS SIMD (with fused-multiply add)")
 
-    gmx_test_avx_gcc_maskload_bug(GMX_SIMD_X86_AVX_GCC_MASKLOAD_BUG "${SIMD_C_FLAGS}")
-
 elseif(GMX_SIMD STREQUAL "AVX_256")
 
     prepare_x86_toolchain(TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS)
@@ -269,8 +265,6 @@ elseif(GMX_SIMD STREQUAL "AVX_256")
     set(GMX_SIMD_X86_${GMX_SIMD} 1)
     set(SIMD_STATUS_MESSAGE "Enabling 256-bit AVX SIMD instructions")
 
-    gmx_test_avx_gcc_maskload_bug(GMX_SIMD_X86_AVX_GCC_MASKLOAD_BUG "${SIMD_C_FLAGS}")
-
 elseif(GMX_SIMD STREQUAL "AVX2_256")
 
     prepare_x86_toolchain(TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS)
@@ -291,8 +285,6 @@ elseif(GMX_SIMD STREQUAL "AVX2_256")
     set(GMX_SIMD_X86_${GMX_SIMD} 1)
     set(SIMD_STATUS_MESSAGE "Enabling 256-bit AVX2 SIMD instructions")
 
-    # No need to test for Maskload bug - it was fixed before gcc added AVX2 support
-
 elseif(GMX_SIMD STREQUAL "MIC")
 
     # No flags needed. Not testing.
@@ -386,7 +378,7 @@ elseif(GMX_SIMD STREQUAL "IBM_QPX")
         set(SIMD_STATUS_MESSAGE "Enabling IBM QPX SIMD instructions")
 
     else()
-        gmx_give_fatal_error_when_simd_support_not_found("IBM QPX" "or 'cmake .. -DCMAKE_TOOLCHAIN_FILE=Platform/BlueGeneQ-static-XL-CXX' to set up the tool chain" "${SUGGEST_BINUTILS_UPDATE}")
+        gmx_give_fatal_error_when_simd_support_not_found("IBM QPX" "or 'cmake .. -DCMAKE_TOOLCHAIN_FILE=Platform/BlueGeneQ-static-bgclang-CXX' to set up the tool chain" "${SUGGEST_BINUTILS_UPDATE}")
     endif()
 
 elseif(GMX_SIMD STREQUAL "IBM_VMX")
index 12ada3d967fdb597064c9bfdd5bc64335e8fff3f..8ef96a298d184c44870bda924db76fc16bf2af90 100644 (file)
 # To help us fund GROMACS development, we humbly ask that you cite
 # the research papers on the package. Check out http://www.gromacs.org.
 
-set(GMX_TNG_MINIMUM_REQUIRED_VERSION "1.7.6")
-set(BUNDLED_TNG_LOCATION "${CMAKE_SOURCE_DIR}/src/external/tng_io")
-if(GMX_USE_TNG)
-    option(GMX_EXTERNAL_TNG "Use external TNG instead of compiling the version shipped with GROMACS." OFF)
+set(GMX_TNG_MINIMUM_REQUIRED_VERSION "1.7.10")
+
+gmx_dependent_option(
+    GMX_EXTERNAL_TNG
+    "Use external TNG instead of compiling the version shipped with GROMACS."
+    OFF
+    GMX_USE_TNG)
+gmx_dependent_option(
+    GMX_EXTERNAL_ZLIB
+    "Use external ZLIB instead of compiling the version shipped with GROMACS as part of TNG."
+    OFF
+    "NOT GMX_EXTERNAL_TNG")
 
+if(GMX_USE_TNG)
     # Detect TNG if GMX_EXTERNAL_TNG is explicitly ON
     if(GMX_EXTERNAL_TNG)
         find_package(TNG_IO ${GMX_TNG_MINIMUM_REQUIRED_VERSION})
         if(NOT TNG_IO_FOUND)
             message(FATAL_ERROR "TNG >= ${GMX_TNG_MINIMUM_REQUIRED_VERSION} not found. You can set GMX_EXTERNAL_TNG=OFF to compile the TNG bundled with GROMACS.")
         endif()
-        include_directories(SYSTEM ${TNG_IO_INCLUDE_DIRS})
     else()
-        include(${BUNDLED_TNG_LOCATION}/BuildTNG.cmake)
-        tng_get_source_list(TNG_SOURCES TNG_IO_DEFINITIONS)
-
-        if (HAVE_ZLIB)
-            list(APPEND GMX_EXTRA_LIBRARIES ${ZLIB_LIBRARIES})
-            include_directories(SYSTEM ${ZLIB_INCLUDE_DIRS})
+        # Detect zlib if the user requires us to use an external
+        # version. If found, it can be used by TNG.
+        if(GMX_EXTERNAL_ZLIB)
+            find_package(ZLIB)
+            if(NOT ZLIB_FOUND)
+                message(FATAL_ERROR "External zlib compression library was required but could not be found. Set GMX_EXTERNAL_ZLIB=OFF to compile zlib as part of GROMACS.")
+            endif()
+            include(gmxTestZLib)
+            gmx_test_zlib(HAVE_ZLIB)
+            if(NOT HAVE_ZLIB)
+                message(FATAL_ERROR "External zlib compression library was required but could not compile and link. Set GMX_EXTERNAL_ZLIB=OFF to compile zlib as part of GROMACS.")
+            endif()
         endif()
     endif()
-else()
-    # We still need to get tng/tng_io_fwd.h from somewhere!
-    include_directories(BEFORE ${BUNDLED_TNG_LOCATION}/include)
 endif()
 
+function(gmx_setup_tng_for_libgromacs)
+    set(BUNDLED_TNG_LOCATION "${CMAKE_SOURCE_DIR}/src/external/tng_io")
+    if (GMX_USE_TNG)
+        if (GMX_EXTERNAL_TNG)
+            target_link_libraries(libgromacs PRIVATE tng_io::tng_io)
+        else()
+            set(_zlib_arg)
+            if (NOT GMX_EXTERNAL_ZLIB)
+                set(_zlib_arg OWN_ZLIB)
+            endif()
+            include(${BUNDLED_TNG_LOCATION}/BuildTNG.cmake)
+            add_tng_io_library(tng_io OBJECT ${_zlib_arg})
+            add_library(tng_io::tng_io ALIAS tng_io)
+            target_link_libraries(libgromacs PRIVATE $<BUILD_INTERFACE:tng_io::tng_io>)
+        endif()
+    endif()
+endfunction()
diff --git a/cmake/gmxTestAVXMaskload.cmake b/cmake/gmxTestAVXMaskload.cmake
deleted file mode 100644 (file)
index a522d6c..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-#
-# This file is part of the GROMACS molecular simulation package.
-#
-# Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by
-# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
-# and including many others, as listed in the AUTHORS file in the
-# top-level source directory and at http://www.gromacs.org.
-#
-# GROMACS is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public License
-# as published by the Free Software Foundation; either version 2.1
-# of the License, or (at your option) any later version.
-#
-# GROMACS is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with GROMACS; if not, see
-# http://www.gnu.org/licenses, or write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
-#
-# If you want to redistribute modifications to GROMACS, please
-# consider that scientific software is very special. Version
-# control is crucial - bugs must be traceable. We will be happy to
-# consider code for inclusion in the official distribution, but
-# derived work must not be called official GROMACS. Details are found
-# in the README & COPYING files - if they are missing, get the
-# official version at http://www.gromacs.org.
-#
-# To help us fund GROMACS development, we humbly ask that you cite
-# the research papers on the package. Check out http://www.gromacs.org.
-
-#  GMX_TEST_AVX_GCC_MASKLOAD_BUG(VARIABLE AVX_CFLAGS)
-#
-#  VARIABLE will be set if the compiler is a buggy version
-#  of GCC (prior to 4.5.3, and maybe 4.6) that has an incorrect second
-#  argument to the AVX _mm256_maskload_ps() intrinsic.
-#
-#  You need to use this variable in a cmakedefine, and then handle
-#  the case separately in your code - no automatic cure, unfortunately.
-#
-MACRO(GMX_TEST_AVX_GCC_MASKLOAD_BUG VARIABLE AVX_CFLAGS)
-    IF(NOT DEFINED ${VARIABLE})
-        MESSAGE(STATUS "Checking for gcc AVX maskload bug")
-        # some compilers like clang accept both cases, 
-        # so first try a normal compile to avoid flagging those as buggy.
-        TRY_COMPILE(${VARIABLE}_COMPILEOK "${CMAKE_BINARY_DIR}"
-                    "${CMAKE_SOURCE_DIR}/cmake/TestAVXMaskload.c"
-                    COMPILE_DEFINITIONS "${AVX_CFLAGS} -DGMX_SIMD_X86_AVX_GCC_MASKLOAD_BUG=0" )
-        IF(${VARIABLE}_COMPILEOK)
-            SET(${VARIABLE} 0 CACHE INTERNAL "Work around GCC bug in AVX maskload argument" FORCE)
-            MESSAGE(STATUS "Checking for gcc AVX maskload bug - not present")
-        ELSE()
-            TRY_COMPILE(${VARIABLE}_COMPILEOK "${CMAKE_BINARY_DIR}"
-                        "${CMAKE_SOURCE_DIR}/cmake/TestAVXMaskload.c"
-                         COMPILE_DEFINITIONS "${AVX_CFLAGS} -DGMX_SIMD_X86_AVX_GCC_MASKLOAD_BUG=1" )
-            IF(${VARIABLE}_COMPILEOK)
-                SET(${VARIABLE} 1 CACHE INTERNAL "Work around GCC bug in AVX maskload argument" FORCE)
-                MESSAGE(STATUS "Checking for gcc AVX maskload bug - found, will try to work around")
-            ELSE()
-                MESSAGE(WARNING "Cannot compile AVX code - assuming gcc AVX maskload bug not present." )
-                MESSAGE(STATUS "Checking for gcc AVX maskload bug - not present")
-            ENDIF()
-        ENDIF()
-    ENDIF()
-ENDMACRO()
index 65a15984634ba80982868dec654aaed2ff211ae9..ea6bed874f22bf5500c1ca78e2ba70a8d55dd763 100644 (file)
@@ -45,11 +45,11 @@ function(GMX_TEST_CXX11 CXX11_CXX_FLAG_NAME STDLIB_CXX_FLAG_NAME STDLIB_LIBRARIE
     # First check that the compiler is OK, and find the appropriate flag.
 
     if(WIN32 AND NOT MINGW)
-        set(CXX11_CXX_FLAG "/Qstd=c++0x")
+        set(CXX11_CXX_FLAG "/Qstd=c++11")
     elseif(CYGWIN)
-        set(CXX11_CXX_FLAG "-std=gnu++0x") #required for strdup
+        set(CXX11_CXX_FLAG "-std=gnu++11") #required for strdup
     else()
-        set(CXX11_CXX_FLAG "-std=c++0x")
+        set(CXX11_CXX_FLAG "-std=c++11")
     endif()
     CHECK_CXX_COMPILER_FLAG("${CXX11_CXX_FLAG}" CXXFLAG_STD_CXX0X)
     if(NOT CXXFLAG_STD_CXX0X)
@@ -106,7 +106,26 @@ int main() {
   int array[5] = { 1, 2, 3, 4, 5 };
   for (int& x : array)
     x *= 2;
+  // Test alignas
+  alignas(4*sizeof(int)) int y;
 }" CXX11_SUPPORTED)
+    if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+        if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.8.1")
+            message(FATAL_ERROR "GROMACS requires version 4.8.1 or later of the GNU C++ compiler for complete C++11 support")
+        endif()
+    elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+        if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "3.3")
+            message(FATAL_ERROR "GROMACS requires version 3.3 or later of the Clang C++ compiler for complete C++11 support")
+        endif()
+    elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
+        if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "15.0")
+            message(FATAL_ERROR "GROMACS requires version 15.0 or later of the Intel C++ compiler for complete C++11 support")
+        endif()
+    elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
+        if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.0.23026")
+            message(FATAL_ERROR "GROMACS requires version 2015 (19.0.23026) or later of the MSVC C++ compiler for complete C++11 support")
+        endif()
+    endif()
     if(CXX11_SUPPORTED)
         set(${CXX11_CXX_FLAG_NAME} ${CXX11_CXX_FLAG} PARENT_SCOPE)
     else()
@@ -128,8 +147,8 @@ int main() {
   intPointer p(new int(10));
   std::map<int, std::unique_ptr<int>> m;
   m.insert(std::make_pair(5, std::move(p)));
-  auto start = std::chrono::system_clock::now();
-  if (std::chrono::system_clock::now() - start < std::chrono::seconds(2))
+  auto start = std::chrono::steady_clock::now();
+  if (std::chrono::steady_clock::now() - start < std::chrono::seconds(2))
   {
       std::thread t;
   }
index 80bfc062f3ead631863ba40f09f26e1fada75798..26eeb298df4c1c7497abd12f3dfb906491f6e494 100644 (file)
@@ -44,37 +44,21 @@ macro(gmx_test_compiler_problems)
         message(WARNING "The versions of the C and C++ compilers do not match (${CMAKE_C_COMPILER_VERSION} and ${CMAKE_CXX_COMPILER_VERSION}, respectively). Mixing different C/C++ compilers can cause problems.")
     endif()
 
-    # clang 3.0 is buggy for some unknown reason detected during adding
-    # the SSE2 group kernels for GROMACS 4.6. If we ever work out what
-    # that is, we should replace these tests with a compiler feature test,
-    # update GROMACS Redmine task #1039 and perhaps report a clang bug.
-    #
-    # In the meantime, until we require CMake 2.8.10 we cannot rely on it to detect
-    # the compiler version for us. So we need a manual check for clang 3.0.
-    include(gmxDetectClang30)
-    gmx_detect_clang_3_0(COMPILER_IS_CLANG_3_0)
-    if(COMPILER_IS_CLANG_3_0)
-        message(FATAL_ERROR "Your compiler is clang version 3.0, which is known to be buggy for GROMACS. Use a different compiler.")
-    endif()
-
-    if (CMAKE_C_COMPILER_ID STREQUAL "PGI")
-        message(WARNING "Currently tested PGI compiler versions (up to 15.7) generate binaries that do not pass all regression test, and the generated binaries are significantly slower than with GCC, ICC or Clang. For now we do not recommend PGI beyond development testing - make sure to run the regressiontests.")
-    endif()
+    # Note that we've already tested that the compiler works with C++11
+    if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
 
-    if(CMAKE_COMPILER_IS_GNUCC AND
-            (CMAKE_C_COMPILER_VERSION VERSION_LESS "4.9.0" OR CMAKE_SIZEOF_VOID_P EQUAL 8)
-            AND (WIN32 OR CYGWIN)
-            AND GMX_SIMD MATCHES "AVX" AND NOT GMX_SIMD STREQUAL AVX_128_FMA)
-        message(WARNING "GCC on Windows (GCC older than 4.9 or any version when compiling for 64bit) with AVX (other than AVX_128_FMA) crashes. Choose a different GMX_SIMD or a different compiler.") # GCC bug 49001, 54412.
-    endif()
-
-    if(CMAKE_C_COMPILER_ID MATCHES "Clang" AND WIN32)
-        if(CMAKE_VERSION VERSION_LESS 3.0.0)
-            message(WARNING "Clang on Windows requires cmake 3.0.0")
+        # GCC bug 49001, 54412 on Windows (just warn, since it might be fixed in later versions)
+        if((CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.9.0" OR CMAKE_SIZEOF_VOID_P EQUAL 8)
+           AND (WIN32 OR CYGWIN)
+           AND (GMX_SIMD MATCHES "AVX") AND NOT (GMX_SIMD STREQUAL AVX_128_FMA))
+            message(WARNING "GCC on Windows (GCC older than 4.9 in 32-bit mode, or any version in 64-bit mode) with 256-bit AVX will probably crashes. You might want to choose a different GMX_SIMD or a different compiler.")
         endif()
-        if(CMAKE_C_COMPILER_VERSION VERSION_LESS 3.5.0)
-            message(WARNING "Clang on Windows requires clang 3.5.0")
+    elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+        if(WIN32 AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "3.5.0")
+            message(WARNING "Using Clang on Windows requires Clang 3.5.0")
         endif()
+    elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "PGI")
+        message(WARNING "Currently tested PGI compiler versions (up to 15.7) generate binaries that do not pass all regression test, and the generated binaries are significantly slower than with GCC, ICC or Clang. For now we do not recommend PGI beyond development testing - make sure to run the regressiontests.")
     endif()
 
 endmacro(gmx_test_compiler_problems)
index 700af4ffc3e1885a7f62a72fc4c4013409156f14..e886ff0825c5939310817136906dec0c19ad822a 100644 (file)
 # The main interface to this machinery is the gmx_configure_version_file()
 # CMake function.  The signature is
 #   gmx_configure_version_file(<input> <output>
-#                              [REMOTE_HASH] [SOURCE_FILE]
+#                              [REMOTE_HASH]
 #                              [TARGET <target>]
 #                              [COMMENT <comment>])
 #   <input>      Specify the input and output files as for configure_file().
 #                This variable is much more expensive to initialize than the
 #                others, so this allows local changes in this file to only
 #                compute that value when required if that becomes necessary.
-#   SOURCE_FILE  Signals that <output> will be used as a source file.
-#                The function will set properties for the source file
-#                appropriately to signify that it is generated.
 #   TARGET       By default, this function uses add_custom_command() to
 #                generate the output file.  If TARGET is specified, then
 #                add_custom_target() is used to create a target with the given
 
 # The GROMACS convention is that these are the version number of the next
 # release that is going to be made from this branch.
-set(GMX_VERSION_MAJOR 2016)
-set(GMX_VERSION_PATCH 2)
+set(GMX_VERSION_MAJOR 2017)
+set(GMX_VERSION_PATCH 0)
 # The suffix, on the other hand, is used mainly for betas and release
 # candidates, where it signifies the most recent such release from
 # this branch; it will be empty before the first such release, as well
@@ -204,8 +201,8 @@ set(GMX_VERSION_SUFFIX "")
 # here. The important thing is to minimize the chance of third-party
 # code being able to dynamically link with a version of libgromacs
 # that might not work.
-set(LIBRARY_SOVERSION_MAJOR 2)
-set(LIBRARY_SOVERSION_MINOR 1)
+set(LIBRARY_SOVERSION_MAJOR 3)
+set(LIBRARY_SOVERSION_MINOR 0)
 set(LIBRARY_VERSION ${LIBRARY_SOVERSION_MAJOR}.${LIBRARY_SOVERSION_MINOR}.0)
 
 #####################################################################
@@ -227,8 +224,8 @@ if (NOT SOURCE_IS_SOURCE_DISTRIBUTION AND
 endif()
 
 set(REGRESSIONTEST_VERSION "${GMX_VERSION_STRING}")
-set(REGRESSIONTEST_BRANCH "refs/heads/release-2016")
-set(REGRESSIONTEST_MD5SUM "366438549270d005fa6def6e56ca0256" CACHE INTERNAL "MD5 sum of the regressiontests tarball")
+set(REGRESSIONTEST_BRANCH "refs/heads/master")
+set(REGRESSIONTEST_MD5SUM "366438549270d005fa6def6e56ca0256")
 
 math(EXPR GMX_VERSION_NUMERIC
      "${GMX_VERSION_MAJOR}*10000 + ${GMX_VERSION_PATCH}")
@@ -356,7 +353,7 @@ unset(GMX_VERSION_CENTRAL_BASE_HASH)
 # See documentation at the top of the script.
 function (gmx_configure_version_file INFILE OUTFILE)
     include(CMakeParseArguments)
-    set(_options REMOTE_HASH SOURCE_FILE)
+    set(_options REMOTE_HASH)
     set(_one_value_args COMMENT TARGET)
     set(_multi_value_args EXTRA_VARS)
     cmake_parse_arguments(
@@ -398,7 +395,4 @@ function (gmx_configure_version_file INFILE OUTFILE)
         add_custom_target(${ARG_TARGET} DEPENDS ${OUTFILE} VERBATIM)
         gmx_set_custom_target_output(${ARG_TARGET} ${OUTFILE})
     endif()
-    if (ARG_SOURCE_FILE)
-        set_source_files_properties(${OUTFILE} PROPERTIES GENERATED true)
-    endif()
 endfunction()
diff --git a/cmake/with_asan_opts.sh b/cmake/with_asan_opts.sh
new file mode 100755 (executable)
index 0000000..283368c
--- /dev/null
@@ -0,0 +1,54 @@
+#!/bin/bash
+#
+# This file is part of the GROMACS molecular simulation package.
+#
+# Copyright (c) 2016, by the GROMACS development team, led by
+# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+# and including many others, as listed in the AUTHORS file in the
+# top-level source directory and at http://www.gromacs.org.
+#
+# GROMACS is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1
+# of the License, or (at your option) any later version.
+#
+# GROMACS is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with GROMACS; if not, see
+# http://www.gnu.org/licenses, or write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+#
+# If you want to redistribute modifications to GROMACS, please
+# consider that scientific software is very special. Version
+# control is crucial - bugs must be traceable. We will be happy to
+# consider code for inclusion in the official distribution, but
+# derived work must not be called official GROMACS. Details are found
+# in the README & COPYING files - if they are missing, get the
+# official version at http://www.gromacs.org.
+#
+# To help us fund GROMACS development, we humbly ask that you cite
+# the research papers on the package. Check out http://www.gromacs.org.
+
+while [[ "$1" != "--" ]] ; do
+    extra_opts="$extra_opts $1"
+    shift
+done
+for opt in $ASAN_OPTIONS ; do
+    if [[ "$opt" == log_path=* ]] ; then
+        # CTest gives errors if the file does not exist, but AddressSanitizer
+        # only produces it if it finds issues...
+        log_path="${opt#log_path=}"
+        log_path="${log_path%\"}"
+        log_path="${log_path#\"}"
+        touch ${log_path}.99999
+    fi
+done
+# Suppressions are not currently necessary, but can be introduced like this.
+#path=`dirname $0`
+#export LSAN_OPTIONS="suppressions=$path/../admin/lsan-suppressions.txt"
+export ASAN_OPTIONS="$ASAN_OPTIONS $extra_opts"
+exec "$@"
index ec6e4550ef5366f00ee9f979c5a096bdbcc22b4b..f769fb0cb1fd248af095235c7c62baa9a33e0135 100644 (file)
@@ -141,7 +141,7 @@ if (SPHINX_FOUND)
         EXTRA_VARS
             SPHINX_EXTENSION_PATH RELENG_PATH
             EXPECTED_DOXYGEN_VERSION
-            GMX_CMAKE_MINIMUM_REQUIRED_VERSION REQUIRED_CUDA_VERSION
+            CMAKE_MINIMUM_REQUIRED_VERSION REQUIRED_CUDA_VERSION
             REQUIRED_OPENCL_MIN_VERSION
             REQUIRED_CUDA_COMPUTE_CAPABILITY REGRESSIONTEST_VERSION
             SOURCE_MD5SUM REGRESSIONTEST_MD5SUM_STRING
index a8bbe35e3c153b5f3ceb2bd6655ba3bc489b01b1..b7c216a81be246e658a194a4d1db193d95f1ca11 100644 (file)
@@ -39,7 +39,7 @@ gmx_version_string_full = '@GMX_VERSION_STRING_FULL@'
 regressiontest_version = '@REGRESSIONTEST_VERSION@'
 variables = [
         ('EXPECTED_DOXYGEN_VERSION', '@EXPECTED_DOXYGEN_VERSION@'),
-        ('GMX_CMAKE_MINIMUM_REQUIRED_VERSION', '@GMX_CMAKE_MINIMUM_REQUIRED_VERSION@'),
+        ('CMAKE_MINIMUM_REQUIRED_VERSION', '@CMAKE_MINIMUM_REQUIRED_VERSION@'),
         ('REQUIRED_CUDA_VERSION', '@REQUIRED_CUDA_VERSION@'),
         ('REQUIRED_CUDA_COMPUTE_CAPABILITY', '@REQUIRED_CUDA_COMPUTE_CAPABILITY@'),
         ('REQUIRED_OPENCL_MIN_VERSION', '@REQUIRED_OPENCL_MIN_VERSION@'),
index 94c0012893adb693507dcf2e75bbe6f4d8e4a6f1..58a676adf47f3c9c18cd9246ea6f806306276d19 100644 (file)
@@ -161,6 +161,8 @@ rst_epilog += """
 .. _LAM-MPI: http://www.lam-mpi.org
 .. _OpenMP: http://en.wikipedia.org/wiki/OpenMP
 .. _CMake installation page: http://www.cmake.org/install/
+.. _Ubuntu toolchain ppa page: https://launchpad.net/~ubuntu-toolchain-r/+archive/ubuntu/test
+.. _EPEL page: https://fedoraproject.org/wiki/EPEL
 .. _running CMake: http://www.cmake.org/runningcmake/
 .. _CMake environment variables: http://cmake.org/Wiki/CMake_Useful_Variables#Environment_Variables
 .. _FFTW: http://www.fftw.org
index a86c6cebd6306492d2fe00548329d4767d4c0c9c..ae313c1bfbf1d1340de416bd147c46d3a12cceb2 100644 (file)
@@ -4,7 +4,7 @@ Build system overview
 =====================
 
 The |Gromacs| build system uses CMake (version
-|GMX_CMAKE_MINIMUM_REQUIRED_VERSION| or newer is required) to generate the
+|CMAKE_MINIMUM_REQUIRED_VERSION| or newer is required) to generate the
 actual build system for the build tool choosen by the user.  See CMake
 documentation for general introduction to CMake and how to use it.  This
 documentation focuses on how the |Gromacs| build system is organized and
index d4d3a9edd8b216fb0e464a3c72eef47b7c1255c7..3fc98799c775d3692e71b8ba5caa48251923c877 100644 (file)
@@ -10,8 +10,9 @@ these standards fully.
 
 * MSVC supports only a subset of C99 and work-arounds are required in those cases.
 * Before 7.0 (partial support in 6.5) CUDA didn't support C++11. Therefore any
-  header file which is needed (or likly will be nedded) by CUDA should not use C++11.
-* C++11 features which are not widely implemented (including in MSVC 2015 and GCC 4.6)
-  should not be used.
+  header file which is needed (or likely will be nedded) by CUDA should not use C++11.
+* We should be able to use virtually all C++ features outside of the header files
+  required by CUDA code (and OpenCL kernels), since we have gradually moved to
+  compilers that have full support for C++11.
 
 .. TODO: Copy important points from http://www.gromacs.org/index.php?title=Developer_Zone/Programming_Guide/Allowed_C%2B%2B_Features
index 50d5460e3fdb95a6c5e561e20197939cc221c690..3ce003eed2c41a5ee012a82a42ebfaac104e3ebb 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by
+# Copyright (c) 2012,2013,2014,2015,2016, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -144,7 +144,7 @@ if (DOXYGEN_FOUND)
             COMMAND ${CMAKE_COMMAND} -DDOCTYPE=${TYPE} -P RunDoxygen.cmake
             DEPENDS ${_deps}
             WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
-            COMMENT "${COMMENT}")
+            COMMENT "${COMMENT}" USES_TERMINAL)
         if (_fast_arg)
             add_dependencies(${TARGET}-fast doxygen-version)
         endif()
@@ -171,7 +171,8 @@ if (DOXYGEN_FOUND)
                 ${CMAKE_CURRENT_SOURCE_DIR}/gmxtree.py
                 ${CMAKE_CURRENT_SOURCE_DIR}/graphbuilder.py
                 ${CMAKE_CURRENT_SOURCE_DIR}/cycle-suppressions.txt
-            COMMENT "Generating include dependency graphs for dot")
+            COMMENT "Generating include dependency graphs for dot"
+            USES_TERMINAL)
 
         # Add separate targets for converting the .dot files to .png.
         # These are not needed by the Doxygen targets, but are useful for
@@ -212,9 +213,9 @@ if (DOXYGEN_FOUND)
             --ignore ${CMAKE_CURRENT_SOURCE_DIR}/suppressions.txt
             --ignore-cycles ${CMAKE_CURRENT_SOURCE_DIR}/cycle-suppressions.txt)
         add_custom_target(check-source      COMMAND ${check_source_command}
-            COMMENT "Checking source code for various issues" VERBATIM)
+            COMMENT "Checking source code for various issues" VERBATIM USES_TERMINAL)
         add_custom_target(check-source-fast COMMAND ${check_source_command}
-            COMMENT "Checking source code for various issues" VERBATIM)
+            COMMENT "Checking source code for various issues" VERBATIM USES_TERMINAL)
         add_dependencies(check-source       doxygen-xml)
     endif()
 else()
index f3f8b77a7b6f96aa2e860cecf1c9bd71378de3d0..92ac3371085610774d5b04319d3f9ded0058a34c 100755 (executable)
@@ -105,7 +105,8 @@ class GroupedSorter(object):
             'time.h']
     _std_c_cpp_headers = ['c' + x[:-2] for x in _std_c_headers]
     _std_cpp_headers = ['algorithm', 'array', 'chrono', 'deque', 'exception', 'fstream',
-            'functional', 'iomanip', 'ios', 'iosfwd', 'iostream', 'istream', 'iterator',
+            'functional', 'initializer_list', 'iomanip', 'ios', 'iosfwd',
+            'iostream', 'istream', 'iterator',
             'limits', 'list', 'map', 'memory', 'new', 'numeric', 'ostream', 'random',
             'regex', 'set', 'sstream', 'stdexcept', 'streambuf', 'string', 'strstream',
             'thread', 'tuple', 'type_traits', 'typeindex', 'typeinfo', 'vector', 'utility']
diff --git a/docs/doxygen/lib/logging.md b/docs/doxygen/lib/logging.md
new file mode 100644 (file)
index 0000000..7cdc697
--- /dev/null
@@ -0,0 +1,53 @@
+Logging {#page_logging}
+=======
+
+Currently, mdrun is using a combination of direct C-style I/O into `fplog` and
+`stderr`, and the facilities described here.  However, more and more should get
+moved to this interface in the future.
+
+The parts that make up the logging system are shown below.
+
+\dot
+    digraph logging_overview {
+        builder [label="LoggerBuilder", URL="\ref gmx::LoggerBuilder"]
+        owner [label="LoggerOwner", URL="\ref gmx::LoggerOwner"]
+        logger [label="MDLogger", URL="\ref gmx::MDLogger"]
+        target [label="ILogTarget", URL="\ref gmx::ILogTarget"]
+        user [label="using code"]
+
+        builder -> owner [label="builds"]
+        owner -> logger
+        owner -> target [label="owns"]
+        logger -> target [label="references"]
+        user -> builder [label="set logging targets"]
+        user -> logger [label="write with\nGMX_LOG()"]
+    }
+\enddot
+
+To initialize the logging system, the using code creates an instance of
+gmx::LoggerBuilder, and sets the desired logging targets with provided methods.
+Once all targets have been initialized, the code calls
+gmx::LoggerBuilder::build() and gets a gmx::LoggerOwner, which is responsible
+of managing the memory allocated for the logger.
+
+To log information, the using code uses an gmx::MDLogger returned by
+gmx::LoggerOwner::logger() with the ::GMX_LOG macro.  Code that writes to the
+log only needs to know of this class (and helper classes used to implement the
+macro), which is a relatively simple container for references to the logging
+targets.  If there is no log target that would consume the information written
+with ::GMX_LOG, the whole statement evaluates to a conditional that reads the
+log target from a member variable and compares it against `nullptr`.  All the
+code that formats the output is skipped in this case.
+
+Currently the implementation is geared to making ::GMX_LOG behavior stable, and
+to be relatively extensible.  However, using any other approach than ::GMX_LOG
+for writing to the log should first think about how the API could be best
+organized for that.
+
+All information written to the log is composed of _log entries_.  Each
+::GMX_LOG statement writes a single log entry, meaning that newlines are
+automatically added.
+
+The logging methods are not thread-safe, so it is the responsibility of the
+calling code to only use them from a single thread or otherwise synchronize
+access.
index 7cca467b7bf7e6682613bac683f2497e994376c2..81c4501d8b8cf07ed29f2625f2b357092e051db6 100644 (file)
@@ -77,6 +77,15 @@ reference data, it will generate a non-fatal Google Test failure in the current
 test.  The test can naturally also use its own test assertions for additional
 checks, but any mismatch will automatically also fail the test.
 
+It is also possible to read values of the reference data items using
+gmx::test::TestReferenceChecker, so that they can be used programmatically.
+For this to work, those items should first be written in the same test.
+This supports tests that want to both check data against a reference, and use
+that reference as a persistence layer for storing information.  This is useful
+at least for serialization tests.
+This is currently not supported for all use cases, but with some caveats, it is
+possible to use this for testing.
+
 When using floating-point values in reference data, the tolerance for the
 comparison can be influenced with
 gmx::test::TestReferenceChecker::setDefaultTolerance().
index 5aaec1a50fe33f44f037046e7b71e796008e0b11..244613c42af473afaade866da452a7fa32576f3c 100644 (file)
@@ -52,6 +52,8 @@ src/gromacs/simd/impl_sparc64_hpc_ace/impl_sparc64_hpc_ace_common.h: warning: sh
 src/gromacs/simd/tests/scalar.cpp: warning: includes "simd.h" unnecessarily
 src/gromacs/simd/tests/scalar_math.cpp: warning: includes "simd.h" unnecessarily
 src/gromacs/simd/tests/scalar_util.cpp: warning: includes "simd.h" unnecessarily
+src/gromacs/tables/cubicsplinetable.h: warning: includes "simd.h" unnecessarily
+src/gromacs/tables/quadraticsplinetable.h: warning: includes "simd.h" unnecessarily
 
 # These are specific to Folding@Home, and easiest to suppress here
 *: warning: includes non-local file as "corewrap.h"
index 0177a2717a5d932811a452cf69ff672b5889d3fe..82dd8d040c4e8a46d6dc962bc05ea1bec3186bf7 100644 (file)
@@ -60,6 +60,8 @@ give an overview of some of the topics that are documented:
 \if libapi
  - \subpage page_wrapperbinary <br/>
    Provides an overview of how the `gmx` wrapper binary is implemented.
+ - \subpage page_logging <br/>
+   Documentation for logging and status output (for now, within mdrun).
  - \subpage page_simd <br/>
    Documentation about the new SIMD module that makes it possible to write
    highly accelerated CPU code that is still portable.
index 6add227204190e8c0dffa8a43e03f5b92d892e34..9fc01b432e03b38570d5663cf36777408a9f0f88 100644 (file)
@@ -15,7 +15,7 @@ These instructions pertain to building |Gromacs|
 Quick and dirty installation
 ----------------------------
 1. Get the latest version of your C and C++ compilers.
-2. Check that you have CMake version |GMX_CMAKE_MINIMUM_REQUIRED_VERSION| or later.
+2. Check that you have CMake version |CMAKE_MINIMUM_REQUIRED_VERSION| or later.
 3. Get and unpack the latest version of the |Gromacs| tarball.
 4. Make a separate build directory and change to it. 
 5. Run ``cmake`` with the path to the source as an argument
@@ -100,10 +100,11 @@ compiler. We recommend gcc, because it is free, widely available and
 frequently provides the best performance.
 
 You should strive to use the most recent version of your
-compiler. Minimum supported compiler versions are
-* GNU (gcc) 4.6
-* Intel (icc) 14
-* LLVM (clang) 3.4
+compiler. Since we require full C++11 support the minimum supported
+compiler versions are
+* GNU (gcc) 4.8.1
+* Intel (icc) 15.0
+* LLVM (clang) 3.3
 * Microsoft (MSVC) 2015
 Other compilers may work (Cray, Pathscale, older clang) but do
 not offer competitive performance. We recommend against PGI because
@@ -120,7 +121,7 @@ other compilers, read on.
 
 On Linux, both the Intel and clang compiler use the libstdc++ which
 comes with gcc as the default C++ library. For |Gromacs|, we require
-the compiler to support libstc++ version 4.6.1 or higher. To select a
+the compiler to support libstc++ version 4.8.1 or higher. To select a
 particular libstdc++ library, use:
 
 * For Intel: ``-DGMX_STDLIB_CXX_FLAGS=-gcc-name=/path/to/gcc/binary``
@@ -149,6 +150,11 @@ For all non-x86 platforms, your best option is typically to use gcc or
 the vendor's default or recommended compiler, and check for
 specialized information below.
 
+For updated versions of gcc to add to your Linux OS, see
+
+* Ubuntu: `Ubuntu toolchain ppa page`_
+* RHEL/CentOS: `EPEL page`_ or the RedHat Developer Toolset
+
 Compiling with parallelization options
 --------------------------------------
 
@@ -160,8 +166,10 @@ generally built into your compiler and detected automatically.
 GPU support
 ^^^^^^^^^^^
 |Gromacs| has excellent support for NVIDIA GPUs supported via CUDA.
-NVIDIA's CUDA_ version |REQUIRED_CUDA_VERSION| software development kit is required,
-and the latest version is strongly encouraged. NVIDIA GPUs with at
+On Linux with gcc, NVIDIA's CUDA_ version |REQUIRED_CUDA_VERSION|
+software development kit is required, and the latest
+version is strongly encouraged. Using Intel or Microsoft compilers
+requires version 7.0 and 8.0, respectively. NVIDIA GPUs with at
 least NVIDIA compute capability |REQUIRED_CUDA_COMPUTE_CAPABILITY| are
 required, e.g. Fermi, Kepler, Maxwell or Pascal cards. You are strongly recommended to
 get the latest CUDA version and driver supported by your hardware, but
@@ -218,7 +226,7 @@ CMake
 -----
 
 |Gromacs| builds with the CMake build system, requiring at least
-version |GMX_CMAKE_MINIMUM_REQUIRED_VERSION|. You can check whether
+version |CMAKE_MINIMUM_REQUIRED_VERSION|. You can check whether
 CMake is installed, and what version it is, with ``cmake
 --version``. If you need to install CMake, then first check whether
 your platform's package management system provides a suitable version,
@@ -1139,9 +1147,9 @@ much everywhere, it is important that we tell you where we really know
 it works because we have tested it. We do test on Linux, Windows, and
 Mac with a range of compilers and libraries for a range of our
 configuration options. Every commit in our git source code repository
-is currently tested on x86 with gcc versions ranging from 4.6 through
-5.2, and versions 16 of the Intel compiler as well as Clang
-version 3.4 through 3.8. For this, we use a variety of GNU/Linux
+is currently tested on x86 with a number of gcc versions ranging from 4.8.1
+through 6.1, versions 16 of the Intel compiler, and Clang
+versions 3.4 through 3.8. For this, we use a variety of GNU/Linux
 flavors and versions as well as recent versions of Windows. Under
 Windows, we test both MSVC 2015 and version 16 of the Intel compiler.
 For details, you can
index c754382c77b980f7b04224190c7e0f1c6734f0c9..9d515bb51cec15dbcb660aac5fb522c8fb9cf903 100644 (file)
@@ -51,6 +51,10 @@ basis of fixed lists.
 \item   {\em Restraints}: position restraints, angle restraints,
 distance restraints, orientation restraints and dihedral restraints, all
 based on fixed lists. 
+%\ifthenelse{\equal{\gmxlite}{1}}{}{
+\item {\em Applied Forces}:
+externally applied forces, see \chref{special}.
+%}
 \end{enumerate}
 
 \section{Non-bonded interactions}
@@ -1653,7 +1657,43 @@ virtual sites. The energy of the shell particle is then minimized at
 each time step in order to remain on the Born-Oppenheimer surface.
 
 \subsection{Simple polarization}
-This is merely a harmonic potential with equilibrium distance 0.
+This is implemented as a harmonic potential with equilibrium distance
+0.
+The input given in the topology file is the polarizability $\alpha$ (in
+{\gromacs} units) as follows:
+\begin{verbatim}
+[ polarization ]
+; Atom i  j  type  alpha
+1         2  1     0.001
+\end{verbatim}
+in this case the polarizability volume is 0.001 nm$^3$ (or 1
+{\AA$^3$}). In order to compute the harmonic force constant $k_{cs}$
+(where $cs$ stands for core-shell), the
+following is used~\cite{Maaren2001a}:
+\begin{equation}
+k_{cs} ~=~ \frac{q_s^2}{\alpha}
+\end{equation}
+where $q_s$ is the charge on the shell particle.
+
+\subsection{Anharmonic polarization}
+For the development of the Drude force field by Roux and McKerell~\cite{Lopes2013a}
+it was found
+that some particles can overpolarize and this was fixed by introducing
+a higher order term in the polarization energy:
+\begin{eqnarray}
+V_{pol} ~=& \frac{k_{cs}}{2} r_{cs}^2 & r_{cs} \le \delta \\
+            =& \frac{k_{cs}}{2} r_{cs}^2 + k_{hyp} (r_{cs}-\delta)^4 & r_{cs} > \delta
+\end{eqnarray}
+where $\delta$ is a user-defined constant that is set to 0.02 nm for
+anions in the Drude force field~\cite{HYu2010}. Since this original introduction it
+has also been used in other atom types~\cite{Lopes2013a}.
+\begin{verbatim}
+[ polarization ]
+;Atom i j    type   alpha (nm^3)    delta  khyp
+1       2       2       0.001786     0.02  16.736e8
+\end{verbatim}
+The above force constant $k_{hyp}$ corresponds to 4$\cdot$10$^8$
+kcal/mol/nm$^4$, hence the strange number.
 
 \subsection{Water polarization}
 A special potential for water that allows anisotropic polarization of
index b6d97cc0b7ea9305cd09f94464f953ec0651bc66..6cb35bd3c5e96655ac896fe0155117e840ac6056 100644 (file)
@@ -6487,6 +6487,18 @@ pages = {2044--2053}
   pages =        "294--305",
 }
 
+@ARTICLE{HYu2010,
+  author = {Yu, Haibo and Whitfield, Troy W and Harder, Edward and Lamoureux,
+       Guillaume and Vorobyov, Igor and Anisimov, Victor M and {MacKerell,
+       Jr.}, Alexander D and Roux, Benoit},
+  title = {{Simulating Monovalent and Divalent Ions in Aqueous Solution Using
+       a Drude Polarizable Force Field}},
+  journal = BTjctc,
+  year = {2010},
+  volume = {6},
+  pages = {774--786},
+}
+
 @Article{Zettlmeissl83,
   author =       "Gerd Zettlmeissl and Rainer Rudolph and Rainer
                  Jaenicke",
@@ -8748,6 +8760,16 @@ doi = "http://dx.doi.org/10.1016/j.softx.2015.06.001"
        pages = {1986--1994}
 }
 
+@article{Caleman2008a,
+  author = {Caleman, C and van der Spoel, D},
+  title = {{Picosecond Melting of Ice by an Infrared Laser Pulse - A simulation
+       study}},
+  journal = {Angew. Chem., Int. Ed. Engl.},
+  year = {2008},
+  volume = {47},
+  pages = {1417--1420}
+}
+
 @article{Wolf2010,
        author = {Wolf, M.G. and Hoefling, M. and Aponte-Santamar\'{i}a, C. and Grubm\"{u}ller, H. and Groenhof, G.},
        title = {{g\_membed}: Efficient insertion of a membrane protein into an equilibrated lipid bilayer with minimal perturbation},
@@ -8756,3 +8778,12 @@ doi = "http://dx.doi.org/10.1016/j.softx.2015.06.001"
        volume = {31},
        pages = {2169--2174}
 }
+
+@Article{Lopes2013a,
+  author =       {Lopes, Pedro E. M. and Huang, Jing and Shim, Jihyun and Luo, Yun and Li, Hui and Roux, Benoit and MacKerell, Alexander D., Jr.},
+  title =        {Polarizable Force Field for Peptides and Proteins Based on the Classical Drude Oscillator},
+  journal =      {J. Chem. Theory Comput},
+  year =         2013,
+  volume =    9,
+  pages =     {5430-5449}}
+
diff --git a/docs/manual/plots/field.eps b/docs/manual/plots/field.eps
new file mode 100644 (file)
index 0000000..5ac7e7d
--- /dev/null
@@ -0,0 +1,4666 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 5 8 769 591
+%%LanguageLevel: 2
+%%Creator: Grace-5.1.25
+%%CreationDate: Tue Jul  5 08:32:47 2016
+%%DocumentData: Clean8Bit
+%%Orientation: Portrait
+%%Title: field.xvg
+%%For: spoel
+%%DocumentNeededResources: (atend)
+%%EndComments
+%%BeginProlog
+/m {moveto} def
+/l {lineto} def
+/s {stroke} def
+/n {newpath} def
+/c {closepath} def
+/RL {rlineto} def
+/SLW {setlinewidth} def
+/GS {gsave} def
+/GR {grestore} def
+/SC {setcolor} def
+/SGRY {setgray} def
+/SRGB {setrgbcolor} def
+/SD {setdash} def
+/SLC {setlinecap} def
+/SLJ {setlinejoin} def
+/SCS {setcolorspace} def
+/FFSF {findfont setfont} def
+/CC {concat} def
+/PXL {n m 0 0 RL s} def
+/Color0 {1.0000 1.0000 1.0000} def
+/Color1 {0.0000 0.0000 0.0000} def
+/Color2 {1.0000 0.0000 0.0000} def
+/Color3 {0.0000 1.0000 0.0000} def
+/Color4 {0.0000 0.0000 1.0000} def
+/Color5 {1.0000 1.0000 0.0000} def
+/Color6 {0.7373 0.5608 0.5608} def
+/Color7 {0.8627 0.8627 0.8627} def
+/Color8 {0.5804 0.0000 0.8275} def
+/Color9 {0.0000 1.0000 1.0000} def
+/Color10 {1.0000 0.0000 1.0000} def
+/Color11 {1.0000 0.6471 0.0000} def
+/Color12 {0.4471 0.1294 0.7373} def
+/Color13 {0.4039 0.0275 0.2824} def
+/Color14 {0.2510 0.8784 0.8157} def
+/Color15 {0.0000 0.5451 0.0000} def
+/Color16 {0.7529 0.7529 0.7529} def
+/Color17 {0.5059 0.5059 0.5059} def
+/Color18 {0.2588 0.2588 0.2588} def
+/PTRN {
+ /pat_bits exch def 
+ <<
+  /PaintType 2
+  /PatternType 1 /TilingType 1
+  /BBox[0 0 16 16]
+  /XStep 16 /YStep 16
+  /PaintProc {
+   pop
+   16 16 true [-1 0 0 -1 16 16] pat_bits imagemask
+  }
+ >>
+ [0.0016 0 0 0.0016 0 0]
+ makepattern
+} def
+/Pattern0 {<0000000000000000000000000000000000000000000000000000000000000000> PTRN} bind def
+/Pattern1 {<ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff> PTRN} bind def
+/Pattern2 {<eeeeffffbbbbffffeeeeffffbbbbffffeeeeffffbbbbffffeeeeffffbbbbffff> PTRN} bind def
+/Pattern3 {<eeeebbbbeeeebbbbeeeebbbbeeeebbbbeeeebbbbeeeebbbbeeeebbbbeeeebbbb> PTRN} bind def
+/Pattern4 {<5555aaaa5555aaaa5555aaaa5555aaaa5555aaaa5555aaaa5555aaaa5555aaaa> PTRN} bind def
+/Pattern5 {<1111444411114444111144441111444411114444111144441111444411114444> PTRN} bind def
+/Pattern6 {<1111000044440000111100004444000011110000444400001111000044440000> PTRN} bind def
+/Pattern7 {<1010000000000000010100000000000010100000000000000101000000000000> PTRN} bind def
+/Pattern8 {<0000000000000000000000000000000000000000000000000000000000000000> PTRN} bind def
+/Pattern9 {<1e1e0f0f8787c3c3e1e1f0f078783c3c1e1e0f0f8787c3c3e1e1f0f078783c3c> PTRN} bind def
+/Pattern10 {<7878f0f0e1e1c3c387870f0f1e1e3c3c7878f0f0e1e1c3c387870f0f1e1e3c3c> PTRN} bind def
+/Pattern11 {<3333333333333333333333333333333333333333333333333333333333333333> PTRN} bind def
+/Pattern12 {<ffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000> PTRN} bind def
+/Pattern13 {<8181424224241818181824244242818181814242242418181818242442428181> PTRN} bind def
+/Pattern14 {<8080404020201010080804040202010180804040202010100808040402020101> PTRN} bind def
+/Pattern15 {<0101020204040808101020204040808001010202040408081010202040408080> PTRN} bind def
+/Pattern16 {<2222222222222222222222222222222222222222222222222222222222222222> PTRN} bind def
+/Pattern17 {<0000ffff000000000000ffff000000000000ffff000000000000ffff00000000> PTRN} bind def
+/Pattern18 {<2222ffff222222222222ffff222222222222ffff222222222222ffff22222222> PTRN} bind def
+/Pattern19 {<ffffffff33333333ffffffff33333333ffffffff33333333ffffffff33333333> PTRN} bind def
+/Pattern20 {<0f0f0f0f0f0f0f0ff0f0f0f0f0f0f0f00f0f0f0f0f0f0f0ff0f0f0f0f0f0f0f0> PTRN} bind def
+/Pattern21 {<ff00ff00ff00ff00ff00ff00ff00ff0000ff00ff00ff00ff00ff00ff00ff00ff> PTRN} bind def
+/Pattern22 {<8001800180018001800180018001ffffffff8001800180018001800180018001> PTRN} bind def
+/Pattern23 {<c003c003c003c003c003c003ffffffffffffffffc003c003c003c003c003c003> PTRN} bind def
+/Pattern24 {<040404040404ffff404040404040ffff040404040404ffff404040404040ffff> PTRN} bind def
+/Pattern25 {<180018001800180018001800ffffffff001800180018001800180018ffffffff> PTRN} bind def
+/Pattern26 {<1111b8b87c7c3a3a1111a3a3c7c78b8b1111b8b87c7c3a3a1111a3a3c7c78b8b> PTRN} bind def
+/Pattern27 {<101010102828c7c70101010182827c7c101010102828c7c70101010182827c7c> PTRN} bind def
+/Pattern28 {<1c1c121211112121c1c12121111112121c1c121211112121c1c1212111111212> PTRN} bind def
+/Pattern29 {<3e3e414180808080e3e31414080808083e3e414180808080e3e3141408080808> PTRN} bind def
+/Pattern30 {<4848888884848383848488884848383848488888848483838484888848483838> PTRN} bind def
+/Pattern31 {<03030404080808080c0c12122121c0c003030404080808080c0c12122121c0c0> PTRN} bind def
+/ellipsedict 8 dict def
+ellipsedict /mtrx matrix put
+/EARC {
+ ellipsedict begin
+  /endangle exch def
+  /startangle exch def
+  /yrad exch def
+  /xrad exch def
+  /y exch def
+  /x exch def
+  /savematrix mtrx currentmatrix def
+  x y translate
+  xrad yrad scale
+  0 0 1 startangle endangle arc
+  savematrix setmatrix
+ end
+} def
+/TL {
+  /kcomp exch def
+  /linewidth exch def
+  /offset exch def
+  GS
+  0 offset rmoveto
+  linewidth SLW
+  dup stringwidth exch kcomp add exch RL s
+  GR
+} def
+/KINIT
+{
+ /kvector exch def
+ /kid 0 def
+} def
+/KPROC
+{
+ pop pop
+ kvector kid get
+ 0 rmoveto
+ /kid 1 kid add def
+} def
+/DefEncoding [
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /space
+ /exclam
+ /quotedbl
+ /numbersign
+ /dollar
+ /percent
+ /ampersand
+ /quoteright
+ /parenleft
+ /parenright
+ /asterisk
+ /plus
+ /comma
+ /hyphen
+ /period
+ /slash
+ /zero
+ /one
+ /two
+ /three
+ /four
+ /five
+ /six
+ /seven
+ /eight
+ /nine
+ /colon
+ /semicolon
+ /less
+ /equal
+ /greater
+ /question
+ /at
+ /A
+ /B
+ /C
+ /D
+ /E
+ /F
+ /G
+ /H
+ /I
+ /J
+ /K
+ /L
+ /M
+ /N
+ /O
+ /P
+ /Q
+ /R
+ /S
+ /T
+ /U
+ /V
+ /W
+ /X
+ /Y
+ /Z
+ /bracketleft
+ /backslash
+ /bracketright
+ /asciicircum
+ /underscore
+ /grave
+ /a
+ /b
+ /c
+ /d
+ /e
+ /f
+ /g
+ /h
+ /i
+ /j
+ /k
+ /l
+ /m
+ /n
+ /o
+ /p
+ /q
+ /r
+ /s
+ /t
+ /u
+ /v
+ /w
+ /x
+ /y
+ /z
+ /braceleft
+ /bar
+ /braceright
+ /asciitilde
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /space
+ /exclamdown
+ /cent
+ /sterling
+ /currency
+ /yen
+ /brokenbar
+ /section
+ /dieresis
+ /copyright
+ /ordfeminine
+ /guillemotleft
+ /logicalnot
+ /hyphen
+ /registered
+ /macron
+ /degree
+ /plusminus
+ /twosuperior
+ /threesuperior
+ /acute
+ /mu
+ /paragraph
+ /periodcentered
+ /cedilla
+ /onesuperior
+ /ordmasculine
+ /guillemotright
+ /onequarter
+ /onehalf
+ /threequarters
+ /questiondown
+ /Agrave
+ /Aacute
+ /Acircumflex
+ /Atilde
+ /Adieresis
+ /Aring
+ /AE
+ /Ccedilla
+ /Egrave
+ /Eacute
+ /Ecircumflex
+ /Edieresis
+ /Igrave
+ /Iacute
+ /Icircumflex
+ /Idieresis
+ /Eth
+ /Ntilde
+ /Ograve
+ /Oacute
+ /Ocircumflex
+ /Otilde
+ /Odieresis
+ /multiply
+ /Oslash
+ /Ugrave
+ /Uacute
+ /Ucircumflex
+ /Udieresis
+ /Yacute
+ /Thorn
+ /germandbls
+ /agrave
+ /aacute
+ /acircumflex
+ /atilde
+ /adieresis
+ /aring
+ /ae
+ /ccedilla
+ /egrave
+ /eacute
+ /ecircumflex
+ /edieresis
+ /igrave
+ /iacute
+ /icircumflex
+ /idieresis
+ /eth
+ /ntilde
+ /ograve
+ /oacute
+ /ocircumflex
+ /otilde
+ /odieresis
+ /divide
+ /oslash
+ /ugrave
+ /uacute
+ /ucircumflex
+ /udieresis
+ /yacute
+ /thorn
+ /ydieresis
+] def
+%%EndProlog
+%%BeginSetup
+%%EndSetup
+612.00 612.00 scale
+n
+0.0000 0.0000 m
+0.0000 1.0000 l
+1.2941 1.0000 l
+1.2941 0.0000 l
+c
+[/DeviceRGB] SCS
+Color0 SC
+fill
+[/DeviceRGB] SCS
+Color1 SC
+[] 0 SD
+0.0015 SLW
+0 SLC
+0 SLJ
+n
+0.1000 0.5250 m
+0.1003 0.5250 l
+0.1006 0.5250 l
+0.1009 0.5250 l
+0.1011 0.5250 l
+0.1014 0.5250 l
+0.1017 0.5250 l
+0.1020 0.5250 l
+0.1023 0.5250 l
+0.1026 0.5250 l
+0.1029 0.5250 l
+0.1031 0.5250 l
+0.1034 0.5250 l
+0.1037 0.5250 l
+0.1040 0.5250 l
+0.1043 0.5250 l
+0.1046 0.5250 l
+0.1049 0.5250 l
+0.1052 0.5250 l
+0.1054 0.5250 l
+0.1057 0.5250 l
+0.1060 0.5250 l
+0.1063 0.5250 l
+0.1066 0.5250 l
+0.1069 0.5250 l
+0.1072 0.5250 l
+0.1074 0.5250 l
+0.1077 0.5250 l
+0.1080 0.5250 l
+0.1083 0.5250 l
+0.1086 0.5250 l
+0.1089 0.5250 l
+0.1092 0.5250 l
+0.1094 0.5250 l
+0.1097 0.5250 l
+0.1100 0.5250 l
+0.1103 0.5250 l
+0.1106 0.5250 l
+0.1109 0.5250 l
+0.1112 0.5250 l
+0.1114 0.5250 l
+0.1117 0.5250 l
+0.1120 0.5250 l
+0.1123 0.5250 l
+0.1126 0.5250 l
+0.1129 0.5250 l
+0.1132 0.5250 l
+0.1135 0.5250 l
+0.1137 0.5250 l
+0.1140 0.5250 l
+0.1143 0.5250 l
+0.1146 0.5250 l
+0.1149 0.5250 l
+0.1152 0.5250 l
+0.1155 0.5250 l
+0.1157 0.5250 l
+0.1160 0.5250 l
+0.1163 0.5250 l
+0.1166 0.5250 l
+0.1169 0.5250 l
+0.1172 0.5250 l
+0.1175 0.5250 l
+0.1177 0.5250 l
+0.1180 0.5250 l
+0.1183 0.5250 l
+0.1186 0.5250 l
+0.1189 0.5250 l
+0.1192 0.5250 l
+0.1195 0.5250 l
+0.1197 0.5250 l
+0.1200 0.5250 l
+0.1203 0.5250 l
+0.1206 0.5250 l
+0.1209 0.5250 l
+0.1212 0.5250 l
+0.1215 0.5250 l
+0.1218 0.5250 l
+0.1220 0.5250 l
+0.1223 0.5250 l
+0.1226 0.5250 l
+0.1229 0.5250 l
+0.1232 0.5250 l
+0.1235 0.5250 l
+0.1238 0.5250 l
+0.1240 0.5250 l
+0.1243 0.5250 l
+0.1246 0.5250 l
+0.1249 0.5250 l
+0.1252 0.5250 l
+0.1255 0.5250 l
+0.1258 0.5250 l
+0.1260 0.5250 l
+0.1263 0.5250 l
+0.1266 0.5250 l
+0.1269 0.5250 l
+0.1272 0.5250 l
+0.1275 0.5250 l
+0.1278 0.5250 l
+0.1281 0.5250 l
+0.1283 0.5250 l
+0.1286 0.5250 l
+0.1289 0.5250 l
+0.1292 0.5250 l
+0.1295 0.5250 l
+0.1298 0.5250 l
+0.1301 0.5250 l
+0.1303 0.5250 l
+0.1306 0.5250 l
+0.1309 0.5250 l
+0.1312 0.5250 l
+0.1315 0.5250 l
+0.1318 0.5250 l
+0.1321 0.5250 l
+0.1323 0.5250 l
+0.1326 0.5250 l
+0.1329 0.5250 l
+0.1332 0.5250 l
+0.1335 0.5250 l
+0.1338 0.5250 l
+0.1341 0.5250 l
+0.1343 0.5250 l
+0.1346 0.5250 l
+0.1349 0.5250 l
+0.1352 0.5250 l
+0.1355 0.5250 l
+0.1358 0.5250 l
+0.1361 0.5250 l
+0.1364 0.5250 l
+0.1366 0.5250 l
+0.1369 0.5250 l
+0.1372 0.5250 l
+0.1375 0.5250 l
+0.1378 0.5250 l
+0.1381 0.5250 l
+0.1384 0.5250 l
+0.1386 0.5250 l
+0.1389 0.5250 l
+0.1392 0.5250 l
+0.1395 0.5250 l
+0.1398 0.5250 l
+0.1401 0.5250 l
+0.1404 0.5250 l
+0.1406 0.5250 l
+0.1409 0.5250 l
+0.1412 0.5250 l
+0.1415 0.5250 l
+0.1418 0.5250 l
+0.1421 0.5250 l
+0.1424 0.5250 l
+0.1426 0.5250 l
+0.1429 0.5250 l
+0.1432 0.5250 l
+0.1435 0.5250 l
+0.1438 0.5250 l
+0.1441 0.5250 l
+0.1444 0.5250 l
+0.1447 0.5250 l
+0.1449 0.5250 l
+0.1452 0.5250 l
+0.1455 0.5250 l
+0.1458 0.5250 l
+0.1461 0.5250 l
+0.1464 0.5250 l
+0.1467 0.5250 l
+0.1469 0.5250 l
+0.1472 0.5250 l
+0.1475 0.5250 l
+0.1478 0.5250 l
+0.1481 0.5250 l
+0.1484 0.5250 l
+0.1487 0.5250 l
+0.1489 0.5250 l
+0.1492 0.5250 l
+0.1495 0.5250 l
+0.1498 0.5250 l
+0.1501 0.5250 l
+0.1504 0.5250 l
+0.1507 0.5250 l
+0.1509 0.5250 l
+0.1512 0.5250 l
+0.1515 0.5250 l
+0.1518 0.5250 l
+0.1521 0.5250 l
+0.1524 0.5250 l
+0.1527 0.5250 l
+0.1530 0.5250 l
+0.1532 0.5250 l
+0.1535 0.5250 l
+0.1538 0.5250 l
+0.1541 0.5250 l
+0.1544 0.5250 l
+0.1547 0.5250 l
+0.1550 0.5250 l
+0.1552 0.5250 l
+0.1555 0.5250 l
+0.1558 0.5250 l
+0.1561 0.5250 l
+0.1564 0.5250 l
+0.1567 0.5250 l
+0.1570 0.5250 l
+0.1572 0.5250 l
+0.1575 0.5250 l
+0.1578 0.5250 l
+0.1581 0.5250 l
+0.1584 0.5250 l
+0.1587 0.5250 l
+0.1590 0.5250 l
+0.1592 0.5250 l
+0.1595 0.5250 l
+0.1598 0.5250 l
+0.1601 0.5250 l
+0.1604 0.5250 l
+0.1607 0.5250 l
+0.1610 0.5250 l
+0.1613 0.5250 l
+0.1615 0.5250 l
+0.1618 0.5250 l
+0.1621 0.5250 l
+0.1624 0.5250 l
+0.1627 0.5250 l
+0.1630 0.5250 l
+0.1633 0.5250 l
+0.1635 0.5250 l
+0.1638 0.5250 l
+0.1641 0.5250 l
+0.1644 0.5250 l
+0.1647 0.5250 l
+0.1650 0.5250 l
+0.1653 0.5250 l
+0.1655 0.5250 l
+0.1658 0.5250 l
+0.1661 0.5250 l
+0.1664 0.5250 l
+0.1667 0.5250 l
+0.1670 0.5250 l
+0.1673 0.5250 l
+0.1675 0.5250 l
+0.1678 0.5250 l
+0.1681 0.5250 l
+0.1684 0.5250 l
+0.1687 0.5250 l
+0.1690 0.5250 l
+0.1693 0.5250 l
+0.1696 0.5250 l
+0.1698 0.5250 l
+0.1701 0.5250 l
+0.1704 0.5250 l
+0.1707 0.5250 l
+0.1710 0.5250 l
+0.1713 0.5250 l
+0.1716 0.5250 l
+0.1718 0.5250 l
+0.1721 0.5250 l
+0.1724 0.5250 l
+0.1727 0.5250 l
+0.1730 0.5250 l
+0.1733 0.5250 l
+0.1736 0.5250 l
+0.1738 0.5250 l
+0.1741 0.5250 l
+0.1744 0.5250 l
+0.1747 0.5250 l
+0.1750 0.5250 l
+0.1753 0.5250 l
+0.1756 0.5250 l
+0.1758 0.5250 l
+0.1761 0.5250 l
+0.1764 0.5250 l
+0.1767 0.5250 l
+0.1770 0.5250 l
+0.1773 0.5250 l
+0.1776 0.5250 l
+0.1779 0.5250 l
+0.1781 0.5250 l
+0.1784 0.5250 l
+0.1787 0.5250 l
+0.1790 0.5250 l
+0.1793 0.5250 l
+0.1796 0.5250 l
+0.1799 0.5250 l
+0.1801 0.5250 l
+0.1804 0.5250 l
+0.1807 0.5250 l
+0.1810 0.5250 l
+0.1813 0.5250 l
+0.1816 0.5250 l
+0.1819 0.5250 l
+0.1821 0.5250 l
+0.1824 0.5250 l
+0.1827 0.5250 l
+0.1830 0.5250 l
+0.1833 0.5250 l
+0.1836 0.5250 l
+0.1839 0.5250 l
+0.1842 0.5250 l
+0.1844 0.5250 l
+0.1847 0.5250 l
+0.1850 0.5250 l
+0.1853 0.5250 l
+0.1856 0.5250 l
+0.1859 0.5250 l
+0.1862 0.5250 l
+0.1864 0.5250 l
+0.1867 0.5250 l
+0.1870 0.5250 l
+0.1873 0.5250 l
+0.1876 0.5250 l
+0.1879 0.5250 l
+0.1882 0.5250 l
+0.1884 0.5250 l
+0.1887 0.5250 l
+0.1890 0.5250 l
+0.1893 0.5250 l
+0.1896 0.5250 l
+0.1899 0.5250 l
+0.1902 0.5250 l
+0.1904 0.5250 l
+0.1907 0.5251 l
+0.1910 0.5251 l
+0.1913 0.5251 l
+0.1916 0.5251 l
+0.1919 0.5251 l
+0.1922 0.5251 l
+0.1925 0.5251 l
+0.1927 0.5251 l
+0.1930 0.5251 l
+0.1933 0.5251 l
+0.1936 0.5251 l
+0.1939 0.5251 l
+0.1942 0.5251 l
+0.1945 0.5251 l
+0.1947 0.5251 l
+0.1950 0.5251 l
+0.1953 0.5251 l
+0.1956 0.5251 l
+0.1959 0.5251 l
+0.1962 0.5250 l
+0.1965 0.5250 l
+0.1967 0.5250 l
+0.1970 0.5250 l
+0.1973 0.5250 l
+0.1976 0.5250 l
+0.1979 0.5250 l
+0.1982 0.5250 l
+0.1985 0.5250 l
+0.1987 0.5250 l
+0.1990 0.5250 l
+0.1993 0.5250 l
+0.1996 0.5250 l
+0.1999 0.5250 l
+0.2002 0.5250 l
+0.2005 0.5250 l
+0.2008 0.5250 l
+0.2010 0.5250 l
+0.2013 0.5249 l
+0.2016 0.5249 l
+0.2019 0.5249 l
+0.2022 0.5249 l
+0.2025 0.5249 l
+0.2028 0.5249 l
+0.2030 0.5249 l
+0.2033 0.5249 l
+0.2036 0.5249 l
+0.2039 0.5249 l
+0.2042 0.5249 l
+0.2045 0.5249 l
+0.2048 0.5249 l
+0.2050 0.5249 l
+0.2053 0.5249 l
+0.2056 0.5249 l
+0.2059 0.5249 l
+0.2062 0.5249 l
+0.2065 0.5249 l
+0.2068 0.5249 l
+0.2070 0.5249 l
+0.2073 0.5249 l
+0.2076 0.5249 l
+0.2079 0.5249 l
+0.2082 0.5249 l
+0.2085 0.5249 l
+0.2088 0.5249 l
+0.2091 0.5249 l
+0.2093 0.5250 l
+0.2096 0.5250 l
+0.2099 0.5250 l
+0.2102 0.5250 l
+0.2105 0.5250 l
+0.2108 0.5250 l
+0.2111 0.5250 l
+0.2113 0.5250 l
+0.2116 0.5250 l
+0.2119 0.5250 l
+0.2122 0.5250 l
+0.2125 0.5251 l
+0.2128 0.5251 l
+0.2131 0.5251 l
+0.2133 0.5251 l
+0.2136 0.5251 l
+0.2139 0.5251 l
+0.2142 0.5251 l
+0.2145 0.5251 l
+0.2148 0.5251 l
+0.2151 0.5251 l
+0.2153 0.5251 l
+0.2156 0.5251 l
+0.2159 0.5251 l
+0.2162 0.5251 l
+0.2165 0.5252 l
+0.2168 0.5252 l
+0.2171 0.5252 l
+0.2174 0.5252 l
+0.2176 0.5252 l
+0.2179 0.5252 l
+0.2182 0.5252 l
+0.2185 0.5251 l
+0.2188 0.5251 l
+0.2191 0.5251 l
+0.2194 0.5251 l
+0.2196 0.5251 l
+0.2199 0.5251 l
+0.2202 0.5251 l
+0.2205 0.5251 l
+0.2208 0.5251 l
+0.2211 0.5251 l
+0.2214 0.5251 l
+0.2216 0.5251 l
+0.2219 0.5250 l
+0.2222 0.5250 l
+0.2225 0.5250 l
+0.2228 0.5250 l
+0.2231 0.5250 l
+0.2234 0.5250 l
+0.2236 0.5250 l
+0.2239 0.5249 l
+0.2242 0.5249 l
+0.2245 0.5249 l
+0.2248 0.5249 l
+0.2251 0.5249 l
+0.2254 0.5249 l
+0.2257 0.5249 l
+0.2259 0.5248 l
+0.2262 0.5248 l
+0.2265 0.5248 l
+0.2268 0.5248 l
+0.2271 0.5248 l
+0.2274 0.5248 l
+0.2277 0.5248 l
+0.2279 0.5248 l
+0.2282 0.5248 l
+0.2285 0.5248 l
+0.2288 0.5248 l
+0.2291 0.5248 l
+0.2294 0.5248 l
+0.2297 0.5248 l
+0.2299 0.5248 l
+0.2302 0.5248 l
+0.2305 0.5248 l
+0.2308 0.5248 l
+0.2311 0.5248 l
+0.2314 0.5248 l
+0.2317 0.5248 l
+0.2320 0.5248 l
+0.2322 0.5248 l
+0.2325 0.5248 l
+0.2328 0.5249 l
+0.2331 0.5249 l
+0.2334 0.5249 l
+0.2337 0.5249 l
+0.2340 0.5249 l
+0.2342 0.5250 l
+0.2345 0.5250 l
+0.2348 0.5250 l
+0.2351 0.5250 l
+0.2354 0.5250 l
+0.2357 0.5251 l
+0.2360 0.5251 l
+0.2362 0.5251 l
+0.2365 0.5251 l
+0.2368 0.5252 l
+0.2371 0.5252 l
+0.2374 0.5252 l
+0.2377 0.5252 l
+0.2380 0.5252 l
+0.2382 0.5252 l
+0.2385 0.5253 l
+0.2388 0.5253 l
+0.2391 0.5253 l
+0.2394 0.5253 l
+0.2397 0.5253 l
+0.2400 0.5253 l
+0.2403 0.5253 l
+0.2405 0.5253 l
+0.2408 0.5253 l
+0.2411 0.5254 l
+0.2414 0.5254 l
+0.2417 0.5253 l
+0.2420 0.5253 l
+0.2423 0.5253 l
+0.2425 0.5253 l
+0.2428 0.5253 l
+0.2431 0.5253 l
+0.2434 0.5253 l
+0.2437 0.5253 l
+0.2440 0.5253 l
+0.2443 0.5252 l
+0.2445 0.5252 l
+0.2448 0.5252 l
+0.2451 0.5252 l
+0.2454 0.5251 l
+0.2457 0.5251 l
+0.2460 0.5251 l
+0.2463 0.5251 l
+0.2465 0.5250 l
+0.2468 0.5250 l
+0.2471 0.5250 l
+0.2474 0.5249 l
+0.2477 0.5249 l
+0.2480 0.5249 l
+0.2483 0.5248 l
+0.2486 0.5248 l
+0.2488 0.5248 l
+0.2491 0.5247 l
+0.2494 0.5247 l
+0.2497 0.5247 l
+0.2500 0.5247 l
+0.2503 0.5246 l
+0.2506 0.5246 l
+0.2508 0.5246 l
+0.2511 0.5246 l
+0.2514 0.5245 l
+0.2517 0.5245 l
+0.2520 0.5245 l
+0.2523 0.5245 l
+0.2526 0.5245 l
+0.2528 0.5245 l
+0.2531 0.5245 l
+0.2534 0.5245 l
+0.2537 0.5245 l
+0.2540 0.5245 l
+0.2543 0.5245 l
+0.2546 0.5245 l
+0.2548 0.5245 l
+0.2551 0.5245 l
+0.2554 0.5246 l
+0.2557 0.5246 l
+0.2560 0.5246 l
+0.2563 0.5246 l
+0.2566 0.5247 l
+0.2569 0.5247 l
+0.2571 0.5247 l
+0.2574 0.5248 l
+0.2577 0.5248 l
+0.2580 0.5249 l
+0.2583 0.5249 l
+0.2586 0.5250 l
+0.2589 0.5250 l
+0.2591 0.5251 l
+0.2594 0.5251 l
+0.2597 0.5251 l
+0.2600 0.5252 l
+0.2603 0.5252 l
+0.2606 0.5253 l
+0.2609 0.5253 l
+0.2611 0.5254 l
+0.2614 0.5254 l
+0.2617 0.5255 l
+0.2620 0.5255 l
+0.2623 0.5255 l
+0.2626 0.5256 l
+0.2629 0.5256 l
+0.2631 0.5256 l
+0.2634 0.5257 l
+0.2637 0.5257 l
+0.2640 0.5257 l
+0.2643 0.5257 l
+0.2646 0.5257 l
+0.2649 0.5258 l
+0.2652 0.5258 l
+0.2654 0.5258 l
+0.2657 0.5258 l
+0.2660 0.5257 l
+0.2663 0.5257 l
+0.2666 0.5257 l
+0.2669 0.5257 l
+0.2672 0.5257 l
+0.2674 0.5256 l
+0.2677 0.5256 l
+0.2680 0.5256 l
+0.2683 0.5255 l
+0.2686 0.5255 l
+0.2689 0.5254 l
+0.2692 0.5254 l
+0.2694 0.5253 l
+0.2697 0.5252 l
+0.2700 0.5252 l
+0.2703 0.5251 l
+0.2706 0.5251 l
+0.2709 0.5250 l
+0.2712 0.5249 l
+0.2714 0.5248 l
+0.2717 0.5248 l
+0.2720 0.5247 l
+0.2723 0.5246 l
+0.2726 0.5246 l
+0.2729 0.5245 l
+0.2732 0.5244 l
+0.2735 0.5244 l
+0.2737 0.5243 l
+0.2740 0.5243 l
+0.2743 0.5242 l
+0.2746 0.5242 l
+0.2749 0.5241 l
+0.2752 0.5241 l
+0.2755 0.5240 l
+0.2757 0.5240 l
+0.2760 0.5240 l
+0.2763 0.5239 l
+0.2766 0.5239 l
+0.2769 0.5239 l
+0.2772 0.5239 l
+0.2775 0.5239 l
+0.2777 0.5239 l
+0.2780 0.5239 l
+0.2783 0.5240 l
+0.2786 0.5240 l
+0.2789 0.5240 l
+0.2792 0.5241 l
+0.2795 0.5241 l
+0.2797 0.5242 l
+0.2800 0.5242 l
+0.2803 0.5243 l
+0.2806 0.5243 l
+0.2809 0.5244 l
+0.2812 0.5245 l
+0.2815 0.5246 l
+0.2818 0.5247 l
+0.2820 0.5248 l
+0.2823 0.5248 l
+0.2826 0.5249 l
+0.2829 0.5250 l
+0.2832 0.5251 l
+0.2835 0.5252 l
+0.2838 0.5253 l
+0.2840 0.5254 l
+0.2843 0.5255 l
+0.2846 0.5256 l
+0.2849 0.5257 l
+0.2852 0.5258 l
+0.2855 0.5259 l
+0.2858 0.5260 l
+0.2860 0.5261 l
+0.2863 0.5262 l
+0.2866 0.5262 l
+0.2869 0.5263 l
+0.2872 0.5263 l
+0.2875 0.5264 l
+0.2878 0.5264 l
+0.2881 0.5265 l
+0.2883 0.5265 l
+0.2886 0.5265 l
+0.2889 0.5266 l
+0.2892 0.5266 l
+0.2895 0.5266 l
+0.2898 0.5265 l
+0.2901 0.5265 l
+0.2903 0.5265 l
+0.2906 0.5264 l
+0.2909 0.5264 l
+0.2912 0.5263 l
+0.2915 0.5263 l
+0.2918 0.5262 l
+0.2921 0.5261 l
+0.2923 0.5260 l
+0.2926 0.5259 l
+0.2929 0.5258 l
+0.2932 0.5257 l
+0.2935 0.5256 l
+0.2938 0.5255 l
+0.2941 0.5253 l
+0.2943 0.5252 l
+0.2946 0.5251 l
+0.2949 0.5249 l
+0.2952 0.5248 l
+0.2955 0.5247 l
+0.2958 0.5245 l
+0.2961 0.5244 l
+0.2964 0.5242 l
+0.2966 0.5241 l
+0.2969 0.5240 l
+0.2972 0.5238 l
+0.2975 0.5237 l
+0.2978 0.5236 l
+0.2981 0.5235 l
+0.2984 0.5234 l
+0.2986 0.5233 l
+0.2989 0.5232 l
+0.2992 0.5231 l
+0.2995 0.5230 l
+0.2998 0.5229 l
+0.3001 0.5229 l
+0.3004 0.5229 l
+0.3006 0.5228 l
+0.3009 0.5228 l
+0.3012 0.5228 l
+0.3015 0.5228 l
+0.3018 0.5228 l
+0.3021 0.5229 l
+0.3024 0.5229 l
+0.3026 0.5230 l
+0.3029 0.5230 l
+0.3032 0.5231 l
+0.3035 0.5232 l
+0.3038 0.5233 l
+0.3041 0.5234 l
+0.3044 0.5236 l
+0.3047 0.5237 l
+0.3049 0.5239 l
+0.3052 0.5240 l
+0.3055 0.5242 l
+0.3058 0.5244 l
+0.3061 0.5245 l
+0.3064 0.5247 l
+0.3067 0.5249 l
+0.3069 0.5251 l
+0.3072 0.5253 l
+0.3075 0.5255 l
+0.3078 0.5257 l
+0.3081 0.5259 l
+0.3084 0.5261 l
+0.3087 0.5263 l
+0.3089 0.5265 l
+0.3092 0.5267 l
+0.3095 0.5268 l
+0.3098 0.5270 l
+0.3101 0.5272 l
+0.3104 0.5273 l
+0.3107 0.5275 l
+0.3109 0.5276 l
+0.3112 0.5277 l
+0.3115 0.5278 l
+0.3118 0.5279 l
+0.3121 0.5280 l
+0.3124 0.5280 l
+0.3127 0.5280 l
+0.3130 0.5281 l
+0.3132 0.5281 l
+0.3135 0.5281 l
+0.3138 0.5280 l
+0.3141 0.5280 l
+0.3144 0.5279 l
+0.3147 0.5278 l
+0.3150 0.5277 l
+0.3152 0.5276 l
+0.3155 0.5275 l
+0.3158 0.5273 l
+0.3161 0.5272 l
+0.3164 0.5270 l
+0.3167 0.5268 l
+0.3170 0.5266 l
+0.3172 0.5263 l
+0.3175 0.5261 l
+0.3178 0.5259 l
+0.3181 0.5256 l
+0.3184 0.5253 l
+0.3187 0.5251 l
+0.3190 0.5248 l
+0.3192 0.5245 l
+0.3195 0.5243 l
+0.3198 0.5240 l
+0.3201 0.5237 l
+0.3204 0.5234 l
+0.3207 0.5232 l
+0.3210 0.5229 l
+0.3213 0.5227 l
+0.3215 0.5224 l
+0.3218 0.5222 l
+0.3221 0.5220 l
+0.3224 0.5218 l
+0.3227 0.5216 l
+0.3230 0.5214 l
+0.3233 0.5213 l
+0.3235 0.5211 l
+0.3238 0.5210 l
+0.3241 0.5209 l
+0.3244 0.5208 l
+0.3247 0.5208 l
+0.3250 0.5208 l
+0.3253 0.5208 l
+0.3255 0.5208 l
+0.3258 0.5208 l
+0.3261 0.5209 l
+0.3264 0.5210 l
+0.3267 0.5211 l
+0.3270 0.5213 l
+0.3273 0.5214 l
+0.3275 0.5216 l
+0.3278 0.5218 l
+0.3281 0.5221 l
+0.3284 0.5223 l
+0.3287 0.5226 l
+0.3290 0.5229 l
+0.3293 0.5232 l
+0.3296 0.5235 l
+0.3298 0.5239 l
+0.3301 0.5242 l
+0.3304 0.5246 l
+0.3307 0.5249 l
+0.3310 0.5253 l
+0.3313 0.5257 l
+0.3316 0.5261 l
+0.3318 0.5264 l
+0.3321 0.5268 l
+0.3324 0.5272 l
+0.3327 0.5275 l
+0.3330 0.5279 l
+0.3333 0.5282 l
+0.3336 0.5286 l
+0.3338 0.5289 l
+0.3341 0.5292 l
+0.3344 0.5295 l
+0.3347 0.5297 l
+0.3350 0.5299 l
+0.3353 0.5302 l
+0.3356 0.5303 l
+0.3359 0.5305 l
+0.3361 0.5306 l
+0.3364 0.5307 l
+0.3367 0.5308 l
+0.3370 0.5308 l
+0.3373 0.5308 l
+0.3376 0.5308 l
+0.3379 0.5307 l
+0.3381 0.5306 l
+0.3384 0.5305 l
+0.3387 0.5303 l
+0.3390 0.5301 l
+0.3393 0.5298 l
+0.3396 0.5296 l
+0.3399 0.5293 l
+0.3401 0.5290 l
+0.3404 0.5286 l
+0.3407 0.5282 l
+0.3410 0.5278 l
+0.3413 0.5274 l
+0.3416 0.5270 l
+0.3419 0.5265 l
+0.3421 0.5260 l
+0.3424 0.5255 l
+0.3427 0.5250 l
+0.3430 0.5245 l
+0.3433 0.5240 l
+0.3436 0.5235 l
+0.3439 0.5230 l
+0.3442 0.5225 l
+0.3444 0.5220 l
+0.3447 0.5215 l
+0.3450 0.5210 l
+0.3453 0.5206 l
+0.3456 0.5201 l
+0.3459 0.5197 l
+0.3462 0.5193 l
+0.3464 0.5189 l
+0.3467 0.5186 l
+0.3470 0.5183 l
+0.3473 0.5180 l
+0.3476 0.5178 l
+0.3479 0.5176 l
+0.3482 0.5174 l
+0.3484 0.5173 l
+0.3487 0.5172 l
+0.3490 0.5172 l
+0.3493 0.5172 l
+0.3496 0.5172 l
+0.3499 0.5173 l
+0.3502 0.5175 l
+0.3504 0.5177 l
+0.3507 0.5179 l
+0.3510 0.5182 l
+0.3513 0.5185 l
+0.3516 0.5189 l
+0.3519 0.5193 l
+0.3522 0.5197 l
+0.3525 0.5202 l
+0.3527 0.5207 l
+0.3530 0.5212 l
+0.3533 0.5218 l
+0.3536 0.5224 l
+0.3539 0.5230 l
+0.3542 0.5237 l
+0.3545 0.5243 l
+0.3547 0.5250 l
+0.3550 0.5257 l
+0.3553 0.5264 l
+0.3556 0.5271 l
+0.3559 0.5278 l
+0.3562 0.5284 l
+0.3565 0.5291 l
+0.3567 0.5298 l
+0.3570 0.5304 l
+0.3573 0.5310 l
+0.3576 0.5316 l
+0.3579 0.5322 l
+0.3582 0.5327 l
+0.3585 0.5332 l
+0.3587 0.5336 l
+0.3590 0.5341 l
+0.3593 0.5344 l
+0.3596 0.5347 l
+0.3599 0.5350 l
+0.3602 0.5352 l
+0.3605 0.5353 l
+0.3608 0.5354 l
+0.3610 0.5355 l
+0.3613 0.5355 l
+0.3616 0.5354 l
+0.3619 0.5352 l
+0.3622 0.5350 l
+0.3625 0.5348 l
+0.3628 0.5344 l
+0.3630 0.5341 l
+0.3633 0.5336 l
+0.3636 0.5331 l
+0.3639 0.5326 l
+0.3642 0.5320 l
+0.3645 0.5313 l
+0.3648 0.5306 l
+0.3650 0.5299 l
+0.3653 0.5291 l
+0.3656 0.5283 l
+0.3659 0.5275 l
+0.3662 0.5266 l
+0.3665 0.5258 l
+0.3668 0.5249 l
+0.3670 0.5240 l
+0.3673 0.5230 l
+0.3676 0.5221 l
+0.3679 0.5212 l
+0.3682 0.5203 l
+0.3685 0.5194 l
+0.3688 0.5186 l
+0.3691 0.5177 l
+0.3693 0.5169 l
+0.3696 0.5161 l
+0.3699 0.5154 l
+0.3702 0.5147 l
+0.3705 0.5141 l
+0.3708 0.5135 l
+0.3711 0.5129 l
+0.3713 0.5125 l
+0.3716 0.5121 l
+0.3719 0.5117 l
+0.3722 0.5115 l
+0.3725 0.5113 l
+0.3728 0.5112 l
+0.3731 0.5111 l
+0.3733 0.5112 l
+0.3736 0.5113 l
+0.3739 0.5115 l
+0.3742 0.5118 l
+0.3745 0.5121 l
+0.3748 0.5126 l
+0.3751 0.5131 l
+0.3753 0.5137 l
+0.3756 0.5144 l
+0.3759 0.5151 l
+0.3762 0.5159 l
+0.3765 0.5167 l
+0.3768 0.5177 l
+0.3771 0.5186 l
+0.3774 0.5197 l
+0.3776 0.5207 l
+0.3779 0.5218 l
+0.3782 0.5230 l
+0.3785 0.5241 l
+0.3788 0.5253 l
+0.3791 0.5265 l
+0.3794 0.5277 l
+0.3796 0.5289 l
+0.3799 0.5301 l
+0.3802 0.5313 l
+0.3805 0.5324 l
+0.3808 0.5336 l
+0.3811 0.5347 l
+0.3814 0.5357 l
+0.3816 0.5367 l
+0.3819 0.5377 l
+0.3822 0.5386 l
+0.3825 0.5394 l
+0.3828 0.5402 l
+0.3831 0.5409 l
+0.3834 0.5415 l
+0.3836 0.5420 l
+0.3839 0.5424 l
+0.3842 0.5427 l
+0.3845 0.5430 l
+0.3848 0.5431 l
+0.3851 0.5431 l
+0.3854 0.5431 l
+0.3857 0.5429 l
+0.3859 0.5426 l
+0.3862 0.5422 l
+0.3865 0.5417 l
+0.3868 0.5411 l
+0.3871 0.5404 l
+0.3874 0.5397 l
+0.3877 0.5388 l
+0.3879 0.5378 l
+0.3882 0.5368 l
+0.3885 0.5356 l
+0.3888 0.5344 l
+0.3891 0.5331 l
+0.3894 0.5318 l
+0.3897 0.5304 l
+0.3899 0.5290 l
+0.3902 0.5275 l
+0.3905 0.5260 l
+0.3908 0.5244 l
+0.3911 0.5229 l
+0.3914 0.5213 l
+0.3917 0.5198 l
+0.3920 0.5182 l
+0.3922 0.5167 l
+0.3925 0.5152 l
+0.3928 0.5137 l
+0.3931 0.5123 l
+0.3934 0.5109 l
+0.3937 0.5096 l
+0.3940 0.5084 l
+0.3942 0.5072 l
+0.3945 0.5062 l
+0.3948 0.5052 l
+0.3951 0.5044 l
+0.3954 0.5036 l
+0.3957 0.5029 l
+0.3960 0.5024 l
+0.3962 0.5020 l
+0.3965 0.5017 l
+0.3968 0.5016 l
+0.3971 0.5016 l
+0.3974 0.5017 l
+0.3977 0.5019 l
+0.3980 0.5023 l
+0.3982 0.5028 l
+0.3985 0.5035 l
+0.3988 0.5043 l
+0.3991 0.5052 l
+0.3994 0.5062 l
+0.3997 0.5073 l
+0.4000 0.5086 l
+0.4003 0.5100 l
+0.4005 0.5115 l
+0.4008 0.5130 l
+0.4011 0.5147 l
+0.4014 0.5164 l
+0.4017 0.5182 l
+0.4020 0.5201 l
+0.4023 0.5220 l
+0.4025 0.5240 l
+0.4028 0.5260 l
+0.4031 0.5280 l
+0.4034 0.5300 l
+0.4037 0.5320 l
+0.4040 0.5340 l
+0.4043 0.5359 l
+0.4045 0.5378 l
+0.4048 0.5397 l
+0.4051 0.5415 l
+0.4054 0.5433 l
+0.4057 0.5449 l
+0.4060 0.5465 l
+0.4063 0.5479 l
+0.4065 0.5493 l
+0.4068 0.5505 l
+0.4071 0.5516 l
+0.4074 0.5525 l
+0.4077 0.5533 l
+0.4080 0.5540 l
+0.4083 0.5545 l
+0.4086 0.5548 l
+0.4088 0.5550 l
+0.4091 0.5550 l
+0.4094 0.5548 l
+0.4097 0.5545 l
+0.4100 0.5539 l
+0.4103 0.5533 l
+0.4106 0.5524 l
+0.4108 0.5514 l
+0.4111 0.5502 l
+0.4114 0.5489 l
+0.4117 0.5474 l
+0.4120 0.5457 l
+0.4123 0.5440 l
+0.4126 0.5421 l
+0.4128 0.5400 l
+0.4131 0.5379 l
+0.4134 0.5357 l
+0.4137 0.5334 l
+0.4140 0.5310 l
+0.4143 0.5285 l
+0.4146 0.5260 l
+0.4148 0.5235 l
+0.4151 0.5210 l
+0.4154 0.5184 l
+0.4157 0.5159 l
+0.4160 0.5133 l
+0.4163 0.5108 l
+0.4166 0.5084 l
+0.4169 0.5060 l
+0.4171 0.5038 l
+0.4174 0.5016 l
+0.4177 0.4995 l
+0.4180 0.4975 l
+0.4183 0.4957 l
+0.4186 0.4940 l
+0.4189 0.4925 l
+0.4191 0.4912 l
+0.4194 0.4900 l
+0.4197 0.4890 l
+0.4200 0.4882 l
+0.4203 0.4876 l
+0.4206 0.4872 l
+0.4209 0.4870 l
+0.4211 0.4871 l
+0.4214 0.4873 l
+0.4217 0.4878 l
+0.4220 0.4885 l
+0.4223 0.4894 l
+0.4226 0.4905 l
+0.4229 0.4918 l
+0.4231 0.4934 l
+0.4234 0.4951 l
+0.4237 0.4970 l
+0.4240 0.4991 l
+0.4243 0.5013 l
+0.4246 0.5038 l
+0.4249 0.5063 l
+0.4252 0.5090 l
+0.4254 0.5119 l
+0.4257 0.5148 l
+0.4260 0.5178 l
+0.4263 0.5209 l
+0.4266 0.5241 l
+0.4269 0.5272 l
+0.4272 0.5305 l
+0.4274 0.5337 l
+0.4277 0.5369 l
+0.4280 0.5400 l
+0.4283 0.5431 l
+0.4286 0.5462 l
+0.4289 0.5491 l
+0.4292 0.5520 l
+0.4294 0.5547 l
+0.4297 0.5573 l
+0.4300 0.5597 l
+0.4303 0.5620 l
+0.4306 0.5641 l
+0.4309 0.5659 l
+0.4312 0.5676 l
+0.4314 0.5690 l
+0.4317 0.5702 l
+0.4320 0.5712 l
+0.4323 0.5719 l
+0.4326 0.5723 l
+0.4329 0.5725 l
+0.4332 0.5724 l
+0.4335 0.5721 l
+0.4337 0.5714 l
+0.4340 0.5705 l
+0.4343 0.5694 l
+0.4346 0.5679 l
+0.4349 0.5662 l
+0.4352 0.5643 l
+0.4355 0.5621 l
+0.4357 0.5597 l
+0.4360 0.5570 l
+0.4363 0.5542 l
+0.4366 0.5511 l
+0.4369 0.5479 l
+0.4372 0.5445 l
+0.4375 0.5410 l
+0.4377 0.5373 l
+0.4380 0.5335 l
+0.4383 0.5297 l
+0.4386 0.5257 l
+0.4389 0.5218 l
+0.4392 0.5178 l
+0.4395 0.5138 l
+0.4397 0.5098 l
+0.4400 0.5059 l
+0.4403 0.5020 l
+0.4406 0.4982 l
+0.4409 0.4946 l
+0.4412 0.4911 l
+0.4415 0.4877 l
+0.4418 0.4845 l
+0.4420 0.4816 l
+0.4423 0.4788 l
+0.4426 0.4762 l
+0.4429 0.4740 l
+0.4432 0.4720 l
+0.4435 0.4702 l
+0.4438 0.4688 l
+0.4440 0.4676 l
+0.4443 0.4668 l
+0.4446 0.4663 l
+0.4449 0.4662 l
+0.4452 0.4663 l
+0.4455 0.4668 l
+0.4458 0.4677 l
+0.4460 0.4688 l
+0.4463 0.4703 l
+0.4466 0.4721 l
+0.4469 0.4743 l
+0.4472 0.4767 l
+0.4475 0.4795 l
+0.4478 0.4825 l
+0.4481 0.4858 l
+0.4483 0.4894 l
+0.4486 0.4932 l
+0.4489 0.4972 l
+0.4492 0.5014 l
+0.4495 0.5058 l
+0.4498 0.5104 l
+0.4501 0.5150 l
+0.4503 0.5198 l
+0.4506 0.5246 l
+0.4509 0.5295 l
+0.4512 0.5345 l
+0.4515 0.5394 l
+0.4518 0.5442 l
+0.4521 0.5491 l
+0.4523 0.5538 l
+0.4526 0.5584 l
+0.4529 0.5629 l
+0.4532 0.5672 l
+0.4535 0.5712 l
+0.4538 0.5751 l
+0.4541 0.5787 l
+0.4543 0.5821 l
+0.4546 0.5852 l
+0.4549 0.5879 l
+0.4552 0.5903 l
+0.4555 0.5924 l
+0.4558 0.5941 l
+0.4561 0.5954 l
+0.4564 0.5964 l
+0.4566 0.5969 l
+0.4569 0.5971 l
+0.4572 0.5968 l
+0.4575 0.5961 l
+0.4578 0.5950 l
+0.4581 0.5935 l
+0.4584 0.5916 l
+0.4586 0.5894 l
+0.4589 0.5867 l
+0.4592 0.5836 l
+0.4595 0.5802 l
+0.4598 0.5764 l
+0.4601 0.5724 l
+0.4604 0.5680 l
+0.4606 0.5633 l
+0.4609 0.5583 l
+0.4612 0.5532 l
+0.4615 0.5478 l
+0.4618 0.5422 l
+0.4621 0.5365 l
+0.4624 0.5307 l
+0.4626 0.5248 l
+0.4629 0.5188 l
+0.4632 0.5128 l
+0.4635 0.5068 l
+0.4638 0.5009 l
+0.4641 0.4951 l
+0.4644 0.4893 l
+0.4647 0.4838 l
+0.4649 0.4784 l
+0.4652 0.4732 l
+0.4655 0.4683 l
+0.4658 0.4636 l
+0.4661 0.4593 l
+0.4664 0.4552 l
+0.4667 0.4516 l
+0.4669 0.4483 l
+0.4672 0.4455 l
+0.4675 0.4430 l
+0.4678 0.4410 l
+0.4681 0.4395 l
+0.4684 0.4384 l
+0.4687 0.4378 l
+0.4689 0.4377 l
+0.4692 0.4381 l
+0.4695 0.4390 l
+0.4698 0.4404 l
+0.4701 0.4423 l
+0.4704 0.4447 l
+0.4707 0.4475 l
+0.4709 0.4508 l
+0.4712 0.4546 l
+0.4715 0.4588 l
+0.4718 0.4634 l
+0.4721 0.4684 l
+0.4724 0.4737 l
+0.4727 0.4794 l
+0.4730 0.4854 l
+0.4732 0.4917 l
+0.4735 0.4983 l
+0.4738 0.5050 l
+0.4741 0.5119 l
+0.4744 0.5189 l
+0.4747 0.5261 l
+0.4750 0.5333 l
+0.4752 0.5405 l
+0.4755 0.5477 l
+0.4758 0.5548 l
+0.4761 0.5618 l
+0.4764 0.5687 l
+0.4767 0.5753 l
+0.4770 0.5818 l
+0.4772 0.5879 l
+0.4775 0.5938 l
+0.4778 0.5994 l
+0.4781 0.6045 l
+0.4784 0.6093 l
+0.4787 0.6136 l
+0.4790 0.6174 l
+0.4792 0.6208 l
+0.4795 0.6236 l
+0.4798 0.6259 l
+0.4801 0.6277 l
+0.4804 0.6289 l
+0.4807 0.6295 l
+0.4810 0.6295 l
+0.4813 0.6289 l
+0.4815 0.6278 l
+0.4818 0.6260 l
+0.4821 0.6237 l
+0.4824 0.6208 l
+0.4827 0.6173 l
+0.4830 0.6132 l
+0.4833 0.6086 l
+0.4835 0.6036 l
+0.4838 0.5980 l
+0.4841 0.5919 l
+0.4844 0.5855 l
+0.4847 0.5786 l
+0.4850 0.5714 l
+0.4853 0.5638 l
+0.4855 0.5560 l
+0.4858 0.5480 l
+0.4861 0.5397 l
+0.4864 0.5313 l
+0.4867 0.5228 l
+0.4870 0.5142 l
+0.4873 0.5056 l
+0.4875 0.4971 l
+0.4878 0.4886 l
+0.4881 0.4803 l
+0.4884 0.4722 l
+0.4887 0.4643 l
+0.4890 0.4566 l
+0.4893 0.4494 l
+0.4896 0.4424 l
+0.4898 0.4359 l
+0.4901 0.4299 l
+0.4904 0.4243 l
+0.4907 0.4193 l
+0.4910 0.4148 l
+0.4913 0.4109 l
+0.4916 0.4076 l
+0.4918 0.4050 l
+0.4921 0.4030 l
+0.4924 0.4017 l
+0.4927 0.4011 l
+0.4930 0.4012 l
+0.4933 0.4020 l
+0.4936 0.4035 l
+0.4938 0.4057 l
+0.4941 0.4086 l
+0.4944 0.4121 l
+0.4947 0.4164 l
+0.4950 0.4212 l
+0.4953 0.4267 l
+0.4956 0.4329 l
+0.4959 0.4395 l
+0.4961 0.4467 l
+0.4964 0.4545 l
+0.4967 0.4626 l
+0.4970 0.4712 l
+0.4973 0.4802 l
+0.4976 0.4895 l
+0.4979 0.4990 l
+0.4981 0.5088 l
+0.4984 0.5187 l
+0.4987 0.5288 l
+0.4990 0.5389 l
+0.4993 0.5490 l
+0.4996 0.5590 l
+0.4999 0.5690 l
+0.5001 0.5787 l
+0.5004 0.5882 l
+0.5007 0.5975 l
+0.5010 0.6064 l
+0.5013 0.6149 l
+0.5016 0.6229 l
+0.5019 0.6305 l
+0.5021 0.6375 l
+0.5024 0.6440 l
+0.5027 0.6498 l
+0.5030 0.6549 l
+0.5033 0.6594 l
+0.5036 0.6631 l
+0.5039 0.6661 l
+0.5042 0.6683 l
+0.5044 0.6697 l
+0.5047 0.6702 l
+0.5050 0.6700 l
+0.5053 0.6690 l
+0.5056 0.6671 l
+0.5059 0.6644 l
+0.5062 0.6609 l
+0.5064 0.6566 l
+0.5067 0.6515 l
+0.5070 0.6457 l
+0.5073 0.6391 l
+0.5076 0.6319 l
+0.5079 0.6240 l
+0.5082 0.6155 l
+0.5084 0.6064 l
+0.5087 0.5967 l
+0.5090 0.5866 l
+0.5093 0.5761 l
+0.5096 0.5652 l
+0.5099 0.5541 l
+0.5102 0.5426 l
+0.5104 0.5310 l
+0.5107 0.5193 l
+0.5110 0.5075 l
+0.5113 0.4957 l
+0.5116 0.4841 l
+0.5119 0.4725 l
+0.5122 0.4612 l
+0.5125 0.4502 l
+0.5127 0.4395 l
+0.5130 0.4292 l
+0.5133 0.4194 l
+0.5136 0.4101 l
+0.5139 0.4014 l
+0.5142 0.3934 l
+0.5145 0.3860 l
+0.5147 0.3794 l
+0.5150 0.3735 l
+0.5153 0.3685 l
+0.5156 0.3643 l
+0.5159 0.3610 l
+0.5162 0.3586 l
+0.5165 0.3571 l
+0.5167 0.3566 l
+0.5170 0.3570 l
+0.5173 0.3584 l
+0.5176 0.3607 l
+0.5179 0.3640 l
+0.5182 0.3682 l
+0.5185 0.3733 l
+0.5187 0.3793 l
+0.5190 0.3862 l
+0.5193 0.3939 l
+0.5196 0.4024 l
+0.5199 0.4116 l
+0.5202 0.4216 l
+0.5205 0.4322 l
+0.5208 0.4434 l
+0.5210 0.4551 l
+0.5213 0.4674 l
+0.5216 0.4800 l
+0.5219 0.4929 l
+0.5222 0.5062 l
+0.5225 0.5196 l
+0.5228 0.5331 l
+0.5230 0.5467 l
+0.5233 0.5602 l
+0.5236 0.5737 l
+0.5239 0.5869 l
+0.5242 0.5999 l
+0.5245 0.6126 l
+0.5248 0.6248 l
+0.5250 0.6365 l
+0.5253 0.6477 l
+0.5256 0.6583 l
+0.5259 0.6682 l
+0.5262 0.6773 l
+0.5265 0.6856 l
+0.5268 0.6931 l
+0.5270 0.6997 l
+0.5273 0.7053 l
+0.5276 0.7100 l
+0.5279 0.7136 l
+0.5282 0.7162 l
+0.5285 0.7177 l
+0.5288 0.7181 l
+0.5291 0.7175 l
+0.5293 0.7157 l
+0.5296 0.7129 l
+0.5299 0.7090 l
+0.5302 0.7040 l
+0.5305 0.6980 l
+0.5308 0.6909 l
+0.5311 0.6829 l
+0.5313 0.6740 l
+0.5316 0.6641 l
+0.5319 0.6534 l
+0.5322 0.6419 l
+0.5325 0.6297 l
+0.5328 0.6168 l
+0.5331 0.6033 l
+0.5333 0.5892 l
+0.5336 0.5748 l
+0.5339 0.5599 l
+0.5342 0.5448 l
+0.5345 0.5295 l
+0.5348 0.5140 l
+0.5351 0.4985 l
+0.5353 0.4831 l
+0.5356 0.4678 l
+0.5359 0.4528 l
+0.5362 0.4380 l
+0.5365 0.4237 l
+0.5368 0.4099 l
+0.5371 0.3966 l
+0.5374 0.3840 l
+0.5376 0.3721 l
+0.5379 0.3610 l
+0.5382 0.3507 l
+0.5385 0.3414 l
+0.5388 0.3331 l
+0.5391 0.3258 l
+0.5394 0.3196 l
+0.5396 0.3145 l
+0.5399 0.3105 l
+0.5402 0.3078 l
+0.5405 0.3063 l
+0.5408 0.3060 l
+0.5411 0.3069 l
+0.5414 0.3091 l
+0.5416 0.3125 l
+0.5419 0.3171 l
+0.5422 0.3229 l
+0.5425 0.3300 l
+0.5428 0.3381 l
+0.5431 0.3473 l
+0.5434 0.3577 l
+0.5436 0.3690 l
+0.5439 0.3812 l
+0.5442 0.3944 l
+0.5445 0.4083 l
+0.5448 0.4230 l
+0.5451 0.4383 l
+0.5454 0.4543 l
+0.5457 0.4707 l
+0.5459 0.4875 l
+0.5462 0.5046 l
+0.5465 0.5219 l
+0.5468 0.5394 l
+0.5471 0.5568 l
+0.5474 0.5742 l
+0.5477 0.5914 l
+0.5479 0.6083 l
+0.5482 0.6248 l
+0.5485 0.6408 l
+0.5488 0.6563 l
+0.5491 0.6711 l
+0.5494 0.6852 l
+0.5497 0.6985 l
+0.5499 0.7108 l
+0.5502 0.7222 l
+0.5505 0.7325 l
+0.5508 0.7417 l
+0.5511 0.7497 l
+0.5514 0.7565 l
+0.5517 0.7620 l
+0.5520 0.7662 l
+0.5522 0.7690 l
+0.5525 0.7705 l
+0.5528 0.7706 l
+0.5531 0.7694 l
+0.5534 0.7667 l
+0.5537 0.7627 l
+0.5540 0.7573 l
+0.5542 0.7505 l
+0.5545 0.7425 l
+0.5548 0.7332 l
+0.5551 0.7226 l
+0.5554 0.7109 l
+0.5557 0.6981 l
+0.5560 0.6842 l
+0.5562 0.6694 l
+0.5565 0.6537 l
+0.5568 0.6371 l
+0.5571 0.6199 l
+0.5574 0.6020 l
+0.5577 0.5836 l
+0.5580 0.5648 l
+0.5582 0.5456 l
+0.5585 0.5263 l
+0.5588 0.5068 l
+0.5591 0.4873 l
+0.5594 0.4680 l
+0.5597 0.4489 l
+0.5600 0.4301 l
+0.5603 0.4118 l
+0.5605 0.3940 l
+0.5608 0.3769 l
+0.5611 0.3605 l
+0.5614 0.3450 l
+0.5617 0.3304 l
+0.5620 0.3168 l
+0.5623 0.3044 l
+0.5625 0.2931 l
+0.5628 0.2831 l
+0.5631 0.2744 l
+0.5634 0.2671 l
+0.5637 0.2612 l
+0.5640 0.2568 l
+0.5643 0.2538 l
+0.5645 0.2524 l
+0.5648 0.2525 l
+0.5651 0.2542 l
+0.5654 0.2574 l
+0.5657 0.2621 l
+0.5660 0.2683 l
+0.5663 0.2760 l
+0.5665 0.2852 l
+0.5668 0.2957 l
+0.5671 0.3076 l
+0.5674 0.3207 l
+0.5677 0.3351 l
+0.5680 0.3506 l
+0.5683 0.3672 l
+0.5686 0.3847 l
+0.5688 0.4032 l
+0.5691 0.4223 l
+0.5694 0.4422 l
+0.5697 0.4626 l
+0.5700 0.4834 l
+0.5703 0.5046 l
+0.5706 0.5260 l
+0.5708 0.5475 l
+0.5711 0.5689 l
+0.5714 0.5902 l
+0.5717 0.6112 l
+0.5720 0.6319 l
+0.5723 0.6520 l
+0.5726 0.6715 l
+0.5728 0.6902 l
+0.5731 0.7081 l
+0.5734 0.7250 l
+0.5737 0.7409 l
+0.5740 0.7556 l
+0.5743 0.7691 l
+0.5746 0.7813 l
+0.5748 0.7921 l
+0.5751 0.8014 l
+0.5754 0.8092 l
+0.5757 0.8154 l
+0.5760 0.8200 l
+0.5763 0.8230 l
+0.5766 0.8243 l
+0.5769 0.8239 l
+0.5771 0.8218 l
+0.5774 0.8180 l
+0.5777 0.8126 l
+0.5780 0.8055 l
+0.5783 0.7968 l
+0.5786 0.7866 l
+0.5789 0.7748 l
+0.5791 0.7616 l
+0.5794 0.7469 l
+0.5797 0.7310 l
+0.5800 0.7138 l
+0.5803 0.6955 l
+0.5806 0.6762 l
+0.5809 0.6559 l
+0.5811 0.6348 l
+0.5814 0.6130 l
+0.5817 0.5906 l
+0.5820 0.5678 l
+0.5823 0.5446 l
+0.5826 0.5213 l
+0.5829 0.4978 l
+0.5831 0.4744 l
+0.5834 0.4513 l
+0.5837 0.4284 l
+0.5840 0.4060 l
+0.5843 0.3842 l
+0.5846 0.3631 l
+0.5849 0.3428 l
+0.5852 0.3235 l
+0.5854 0.3052 l
+0.5857 0.2881 l
+0.5860 0.2723 l
+0.5863 0.2578 l
+0.5866 0.2448 l
+0.5869 0.2334 l
+0.5872 0.2235 l
+0.5874 0.2153 l
+0.5877 0.2088 l
+0.5880 0.2041 l
+0.5883 0.2012 l
+0.5886 0.2000 l
+0.5889 0.2008 l
+0.5892 0.2033 l
+0.5894 0.2077 l
+0.5897 0.2139 l
+0.5900 0.2218 l
+0.5903 0.2315 l
+0.5906 0.2429 l
+0.5909 0.2559 l
+0.5912 0.2705 l
+0.5914 0.2866 l
+0.5917 0.3040 l
+0.5920 0.3228 l
+0.5923 0.3428 l
+0.5926 0.3639 l
+0.5929 0.3860 l
+0.5932 0.4089 l
+0.5935 0.4325 l
+0.5937 0.4568 l
+0.5940 0.4815 l
+0.5943 0.5066 l
+0.5946 0.5319 l
+0.5949 0.5572 l
+0.5952 0.5824 l
+0.5955 0.6073 l
+0.5957 0.6319 l
+0.5960 0.6560 l
+0.5963 0.6794 l
+0.5966 0.7020 l
+0.5969 0.7237 l
+0.5972 0.7444 l
+0.5975 0.7638 l
+0.5977 0.7820 l
+0.5980 0.7988 l
+0.5983 0.8141 l
+0.5986 0.8279 l
+0.5989 0.8399 l
+0.5992 0.8502 l
+0.5995 0.8588 l
+0.5998 0.8654 l
+0.6000 0.8702 l
+0.6003 0.8731 l
+0.6006 0.8739 l
+0.6009 0.8729 l
+0.6012 0.8698 l
+0.6015 0.8648 l
+0.6018 0.8579 l
+0.6020 0.8491 l
+0.6023 0.8384 l
+0.6026 0.8259 l
+0.6029 0.8117 l
+0.6032 0.7958 l
+0.6035 0.7783 l
+0.6038 0.7594 l
+0.6040 0.7391 l
+0.6043 0.7175 l
+0.6046 0.6948 l
+0.6049 0.6710 l
+0.6052 0.6464 l
+0.6055 0.6210 l
+0.6058 0.5949 l
+0.6060 0.5684 l
+0.6063 0.5416 l
+0.6066 0.5146 l
+0.6069 0.4876 l
+0.6072 0.4608 l
+0.6075 0.4342 l
+0.6078 0.4080 l
+0.6081 0.3825 l
+0.6083 0.3576 l
+0.6086 0.3337 l
+0.6089 0.3107 l
+0.6092 0.2889 l
+0.6095 0.2684 l
+0.6098 0.2492 l
+0.6101 0.2316 l
+0.6103 0.2156 l
+0.6106 0.2012 l
+0.6109 0.1887 l
+0.6112 0.1780 l
+0.6115 0.1693 l
+0.6118 0.1625 l
+0.6121 0.1577 l
+0.6123 0.1550 l
+0.6126 0.1544 l
+0.6129 0.1559 l
+0.6132 0.1595 l
+0.6135 0.1651 l
+0.6138 0.1728 l
+0.6141 0.1825 l
+0.6143 0.1941 l
+0.6146 0.2076 l
+0.6149 0.2230 l
+0.6152 0.2401 l
+0.6155 0.2588 l
+0.6158 0.2791 l
+0.6161 0.3008 l
+0.6164 0.3239 l
+0.6166 0.3481 l
+0.6169 0.3734 l
+0.6172 0.3996 l
+0.6175 0.4266 l
+0.6178 0.4542 l
+0.6181 0.4823 l
+0.6184 0.5106 l
+0.6186 0.5391 l
+0.6189 0.5676 l
+0.6192 0.5960 l
+0.6195 0.6240 l
+0.6198 0.6515 l
+0.6201 0.6783 l
+0.6204 0.7044 l
+0.6206 0.7295 l
+0.6209 0.7535 l
+0.6212 0.7763 l
+0.6215 0.7977 l
+0.6218 0.8176 l
+0.6221 0.8359 l
+0.6224 0.8525 l
+0.6226 0.8673 l
+0.6229 0.8802 l
+0.6232 0.8911 l
+0.6235 0.9000 l
+0.6238 0.9068 l
+0.6241 0.9114 l
+0.6244 0.9139 l
+0.6247 0.9142 l
+0.6249 0.9123 l
+0.6252 0.9082 l
+0.6255 0.9020 l
+0.6258 0.8936 l
+0.6261 0.8831 l
+0.6264 0.8706 l
+0.6267 0.8561 l
+0.6269 0.8397 l
+0.6272 0.8215 l
+0.6275 0.8016 l
+0.6278 0.7801 l
+0.6281 0.7571 l
+0.6284 0.7328 l
+0.6287 0.7072 l
+0.6289 0.6806 l
+0.6292 0.6530 l
+0.6295 0.6247 l
+0.6298 0.5958 l
+0.6301 0.5664 l
+0.6304 0.5367 l
+0.6307 0.5069 l
+0.6309 0.4771 l
+0.6312 0.4476 l
+0.6315 0.4184 l
+0.6318 0.3898 l
+0.6321 0.3619 l
+0.6324 0.3349 l
+0.6327 0.3089 l
+0.6330 0.2841 l
+0.6332 0.2606 l
+0.6335 0.2385 l
+0.6338 0.2180 l
+0.6341 0.1992 l
+0.6344 0.1822 l
+0.6347 0.1671 l
+0.6350 0.1540 l
+0.6352 0.1430 l
+0.6355 0.1341 l
+0.6358 0.1274 l
+0.6361 0.1229 l
+0.6364 0.1207 l
+0.6367 0.1208 l
+0.6370 0.1231 l
+0.6372 0.1277 l
+0.6375 0.1345 l
+0.6378 0.1436 l
+0.6381 0.1548 l
+0.6384 0.1681 l
+0.6387 0.1835 l
+0.6390 0.2008 l
+0.6392 0.2199 l
+0.6395 0.2408 l
+0.6398 0.2633 l
+0.6401 0.2874 l
+0.6404 0.3128 l
+0.6407 0.3394 l
+0.6410 0.3671 l
+0.6413 0.3958 l
+0.6415 0.4252 l
+0.6418 0.4552 l
+0.6421 0.4857 l
+0.6424 0.5164 l
+0.6427 0.5472 l
+0.6430 0.5779 l
+0.6433 0.6083 l
+0.6435 0.6384 l
+0.6438 0.6678 l
+0.6441 0.6964 l
+0.6444 0.7242 l
+0.6447 0.7508 l
+0.6450 0.7762 l
+0.6453 0.8002 l
+0.6455 0.8227 l
+0.6458 0.8436 l
+0.6461 0.8626 l
+0.6464 0.8798 l
+0.6467 0.8950 l
+0.6470 0.9082 l
+0.6473 0.9192 l
+0.6475 0.9280 l
+0.6478 0.9345 l
+0.6481 0.9388 l
+0.6484 0.9407 l
+0.6487 0.9402 l
+0.6490 0.9375 l
+0.6493 0.9324 l
+0.6496 0.9250 l
+0.6498 0.9153 l
+0.6501 0.9035 l
+0.6504 0.8895 l
+0.6507 0.8734 l
+0.6510 0.8554 l
+0.6513 0.8354 l
+0.6516 0.8137 l
+0.6518 0.7904 l
+0.6521 0.7656 l
+0.6524 0.7393 l
+0.6527 0.7119 l
+0.6530 0.6833 l
+0.6533 0.6539 l
+0.6536 0.6237 l
+0.6538 0.5929 l
+0.6541 0.5617 l
+0.6544 0.5303 l
+0.6547 0.4988 l
+0.6550 0.4675 l
+0.6553 0.4364 l
+0.6556 0.4058 l
+0.6559 0.3759 l
+0.6561 0.3468 l
+0.6564 0.3187 l
+0.6567 0.2917 l
+0.6570 0.2660 l
+0.6573 0.2417 l
+0.6576 0.2191 l
+0.6579 0.1981 l
+0.6581 0.1790 l
+0.6584 0.1618 l
+0.6587 0.1466 l
+0.6590 0.1336 l
+0.6593 0.1227 l
+0.6596 0.1141 l
+0.6599 0.1079 l
+0.6601 0.1039 l
+0.6604 0.1024 l
+0.6607 0.1032 l
+0.6610 0.1064 l
+0.6613 0.1119 l
+0.6616 0.1198 l
+0.6619 0.1299 l
+0.6621 0.1423 l
+0.6624 0.1569 l
+0.6627 0.1735 l
+0.6630 0.1921 l
+0.6633 0.2126 l
+0.6636 0.2349 l
+0.6639 0.2588 l
+0.6642 0.2842 l
+0.6644 0.3110 l
+0.6647 0.3390 l
+0.6650 0.3680 l
+0.6653 0.3979 l
+0.6656 0.4286 l
+0.6659 0.4598 l
+0.6662 0.4914 l
+0.6664 0.5232 l
+0.6667 0.5550 l
+0.6670 0.5867 l
+0.6673 0.6180 l
+0.6676 0.6488 l
+0.6679 0.6789 l
+0.6682 0.7081 l
+0.6684 0.7363 l
+0.6687 0.7634 l
+0.6690 0.7891 l
+0.6693 0.8133 l
+0.6696 0.8359 l
+0.6699 0.8567 l
+0.6702 0.8757 l
+0.6704 0.8927 l
+0.6707 0.9076 l
+0.6710 0.9204 l
+0.6713 0.9310 l
+0.6716 0.9393 l
+0.6719 0.9452 l
+0.6722 0.9488 l
+0.6725 0.9500 l
+0.6727 0.9488 l
+0.6730 0.9452 l
+0.6733 0.9393 l
+0.6736 0.9310 l
+0.6739 0.9204 l
+0.6742 0.9076 l
+0.6745 0.8927 l
+0.6747 0.8757 l
+0.6750 0.8567 l
+0.6753 0.8359 l
+0.6756 0.8133 l
+0.6759 0.7891 l
+0.6762 0.7634 l
+0.6765 0.7363 l
+0.6767 0.7081 l
+0.6770 0.6789 l
+0.6773 0.6488 l
+0.6776 0.6180 l
+0.6779 0.5867 l
+0.6782 0.5550 l
+0.6785 0.5232 l
+0.6787 0.4914 l
+0.6790 0.4598 l
+0.6793 0.4286 l
+0.6796 0.3979 l
+0.6799 0.3680 l
+0.6802 0.3390 l
+0.6805 0.3110 l
+0.6808 0.2842 l
+0.6810 0.2588 l
+0.6813 0.2349 l
+0.6816 0.2126 l
+0.6819 0.1921 l
+0.6822 0.1735 l
+0.6825 0.1569 l
+0.6828 0.1423 l
+0.6830 0.1299 l
+0.6833 0.1198 l
+0.6836 0.1119 l
+0.6839 0.1064 l
+0.6842 0.1032 l
+0.6845 0.1024 l
+0.6848 0.1039 l
+0.6850 0.1079 l
+0.6853 0.1141 l
+0.6856 0.1227 l
+0.6859 0.1336 l
+0.6862 0.1466 l
+0.6865 0.1618 l
+0.6868 0.1790 l
+0.6870 0.1981 l
+0.6873 0.2191 l
+0.6876 0.2417 l
+0.6879 0.2660 l
+0.6882 0.2917 l
+0.6885 0.3187 l
+0.6888 0.3468 l
+0.6891 0.3759 l
+0.6893 0.4058 l
+0.6896 0.4364 l
+0.6899 0.4675 l
+0.6902 0.4988 l
+0.6905 0.5303 l
+0.6908 0.5617 l
+0.6911 0.5929 l
+0.6913 0.6237 l
+0.6916 0.6539 l
+0.6919 0.6833 l
+0.6922 0.7119 l
+0.6925 0.7393 l
+0.6928 0.7656 l
+0.6931 0.7904 l
+0.6933 0.8137 l
+0.6936 0.8354 l
+0.6939 0.8554 l
+0.6942 0.8734 l
+0.6945 0.8895 l
+0.6948 0.9035 l
+0.6951 0.9153 l
+0.6953 0.9250 l
+0.6956 0.9324 l
+0.6959 0.9375 l
+0.6962 0.9402 l
+0.6965 0.9407 l
+0.6968 0.9388 l
+0.6971 0.9345 l
+0.6974 0.9280 l
+0.6976 0.9192 l
+0.6979 0.9082 l
+0.6982 0.8950 l
+0.6985 0.8798 l
+0.6988 0.8626 l
+0.6991 0.8436 l
+0.6994 0.8227 l
+0.6996 0.8002 l
+0.6999 0.7762 l
+0.7002 0.7508 l
+0.7005 0.7242 l
+0.7008 0.6964 l
+0.7011 0.6678 l
+0.7014 0.6384 l
+0.7016 0.6083 l
+0.7019 0.5779 l
+0.7022 0.5472 l
+0.7025 0.5164 l
+0.7028 0.4857 l
+0.7031 0.4552 l
+0.7034 0.4252 l
+0.7037 0.3958 l
+0.7039 0.3671 l
+0.7042 0.3394 l
+0.7045 0.3128 l
+0.7048 0.2874 l
+0.7051 0.2633 l
+0.7054 0.2408 l
+0.7057 0.2199 l
+0.7059 0.2008 l
+0.7062 0.1835 l
+0.7065 0.1681 l
+0.7068 0.1548 l
+0.7071 0.1436 l
+0.7074 0.1345 l
+0.7077 0.1277 l
+0.7079 0.1231 l
+0.7082 0.1208 l
+0.7085 0.1207 l
+0.7088 0.1229 l
+0.7091 0.1274 l
+0.7094 0.1341 l
+0.7097 0.1430 l
+0.7099 0.1540 l
+0.7102 0.1671 l
+0.7105 0.1822 l
+0.7108 0.1992 l
+0.7111 0.2180 l
+0.7114 0.2385 l
+0.7117 0.2606 l
+0.7120 0.2841 l
+0.7122 0.3089 l
+0.7125 0.3349 l
+0.7128 0.3619 l
+0.7131 0.3898 l
+0.7134 0.4184 l
+0.7137 0.4476 l
+0.7140 0.4771 l
+0.7142 0.5069 l
+0.7145 0.5367 l
+0.7148 0.5664 l
+0.7151 0.5958 l
+0.7154 0.6247 l
+0.7157 0.6530 l
+0.7160 0.6806 l
+0.7162 0.7072 l
+0.7165 0.7328 l
+0.7168 0.7571 l
+0.7171 0.7801 l
+0.7174 0.8016 l
+0.7177 0.8215 l
+0.7180 0.8397 l
+0.7182 0.8561 l
+0.7185 0.8706 l
+0.7188 0.8831 l
+0.7191 0.8936 l
+0.7194 0.9020 l
+0.7197 0.9082 l
+0.7200 0.9123 l
+0.7203 0.9142 l
+0.7205 0.9139 l
+0.7208 0.9114 l
+0.7211 0.9068 l
+0.7214 0.9000 l
+0.7217 0.8911 l
+0.7220 0.8802 l
+0.7223 0.8673 l
+0.7225 0.8525 l
+0.7228 0.8359 l
+0.7231 0.8176 l
+0.7234 0.7977 l
+0.7237 0.7763 l
+0.7240 0.7535 l
+0.7243 0.7295 l
+0.7245 0.7044 l
+0.7248 0.6783 l
+0.7251 0.6515 l
+0.7254 0.6240 l
+0.7257 0.5960 l
+0.7260 0.5676 l
+0.7263 0.5391 l
+0.7265 0.5106 l
+0.7268 0.4823 l
+0.7271 0.4542 l
+0.7274 0.4266 l
+0.7277 0.3996 l
+0.7280 0.3734 l
+0.7283 0.3481 l
+0.7286 0.3239 l
+0.7288 0.3008 l
+0.7291 0.2791 l
+0.7294 0.2588 l
+0.7297 0.2401 l
+0.7300 0.2230 l
+0.7303 0.2076 l
+0.7306 0.1941 l
+0.7308 0.1825 l
+0.7311 0.1728 l
+0.7314 0.1651 l
+0.7317 0.1595 l
+0.7320 0.1559 l
+0.7323 0.1544 l
+0.7326 0.1550 l
+0.7328 0.1577 l
+0.7331 0.1625 l
+0.7334 0.1693 l
+0.7337 0.1780 l
+0.7340 0.1887 l
+0.7343 0.2012 l
+0.7346 0.2156 l
+0.7348 0.2316 l
+0.7351 0.2492 l
+0.7354 0.2684 l
+0.7357 0.2889 l
+0.7360 0.3107 l
+0.7363 0.3337 l
+0.7366 0.3576 l
+0.7369 0.3825 l
+0.7371 0.4080 l
+0.7374 0.4342 l
+0.7377 0.4608 l
+0.7380 0.4876 l
+0.7383 0.5146 l
+0.7386 0.5416 l
+0.7389 0.5684 l
+0.7391 0.5949 l
+0.7394 0.6210 l
+0.7397 0.6464 l
+0.7400 0.6710 l
+0.7403 0.6948 l
+0.7406 0.7175 l
+0.7409 0.7391 l
+0.7411 0.7594 l
+0.7414 0.7783 l
+0.7417 0.7958 l
+0.7420 0.8117 l
+0.7423 0.8259 l
+0.7426 0.8384 l
+0.7429 0.8491 l
+0.7431 0.8579 l
+0.7434 0.8648 l
+0.7437 0.8698 l
+0.7440 0.8729 l
+0.7443 0.8739 l
+0.7446 0.8731 l
+0.7449 0.8702 l
+0.7452 0.8654 l
+0.7454 0.8588 l
+0.7457 0.8502 l
+0.7460 0.8399 l
+0.7463 0.8279 l
+0.7466 0.8141 l
+0.7469 0.7988 l
+0.7472 0.7820 l
+0.7474 0.7638 l
+0.7477 0.7444 l
+0.7480 0.7237 l
+0.7483 0.7020 l
+0.7486 0.6794 l
+0.7489 0.6560 l
+0.7492 0.6319 l
+0.7494 0.6073 l
+0.7497 0.5824 l
+0.7500 0.5572 l
+0.7503 0.5319 l
+0.7506 0.5066 l
+0.7509 0.4815 l
+0.7512 0.4568 l
+0.7514 0.4325 l
+0.7517 0.4089 l
+0.7520 0.3859 l
+0.7523 0.3639 l
+0.7526 0.3428 l
+0.7529 0.3228 l
+0.7532 0.3040 l
+0.7535 0.2866 l
+0.7537 0.2705 l
+0.7540 0.2559 l
+0.7543 0.2429 l
+0.7546 0.2315 l
+0.7549 0.2218 l
+0.7552 0.2139 l
+0.7555 0.2077 l
+0.7557 0.2033 l
+0.7560 0.2008 l
+0.7563 0.2000 l
+0.7566 0.2012 l
+0.7569 0.2041 l
+0.7572 0.2088 l
+0.7575 0.2153 l
+0.7577 0.2235 l
+0.7580 0.2334 l
+0.7583 0.2448 l
+0.7586 0.2578 l
+0.7589 0.2723 l
+0.7592 0.2881 l
+0.7595 0.3052 l
+0.7598 0.3235 l
+0.7600 0.3428 l
+0.7603 0.3631 l
+0.7606 0.3842 l
+0.7609 0.4060 l
+0.7612 0.4284 l
+0.7615 0.4513 l
+0.7618 0.4744 l
+0.7620 0.4978 l
+0.7623 0.5213 l
+0.7626 0.5446 l
+0.7629 0.5678 l
+0.7632 0.5906 l
+0.7635 0.6130 l
+0.7638 0.6348 l
+0.7640 0.6559 l
+0.7643 0.6762 l
+0.7646 0.6955 l
+0.7649 0.7138 l
+0.7652 0.7310 l
+0.7655 0.7469 l
+0.7658 0.7616 l
+0.7660 0.7748 l
+0.7663 0.7866 l
+0.7666 0.7968 l
+0.7669 0.8055 l
+0.7672 0.8126 l
+0.7675 0.8180 l
+0.7678 0.8218 l
+0.7681 0.8239 l
+0.7683 0.8243 l
+0.7686 0.8230 l
+0.7689 0.8200 l
+0.7692 0.8154 l
+0.7695 0.8092 l
+0.7698 0.8014 l
+0.7701 0.7921 l
+0.7703 0.7813 l
+0.7706 0.7691 l
+0.7709 0.7556 l
+0.7712 0.7409 l
+0.7715 0.7250 l
+0.7718 0.7081 l
+0.7721 0.6902 l
+0.7723 0.6715 l
+0.7726 0.6520 l
+0.7729 0.6319 l
+0.7732 0.6112 l
+0.7735 0.5902 l
+0.7738 0.5689 l
+0.7741 0.5475 l
+0.7743 0.5260 l
+0.7746 0.5046 l
+0.7749 0.4834 l
+0.7752 0.4626 l
+0.7755 0.4422 l
+0.7758 0.4223 l
+0.7761 0.4032 l
+0.7764 0.3847 l
+0.7766 0.3672 l
+0.7769 0.3506 l
+0.7772 0.3351 l
+0.7775 0.3207 l
+0.7778 0.3076 l
+0.7781 0.2957 l
+0.7784 0.2852 l
+0.7786 0.2760 l
+0.7789 0.2683 l
+0.7792 0.2621 l
+0.7795 0.2574 l
+0.7798 0.2542 l
+0.7801 0.2525 l
+0.7804 0.2524 l
+0.7806 0.2538 l
+0.7809 0.2568 l
+0.7812 0.2612 l
+0.7815 0.2671 l
+0.7818 0.2744 l
+0.7821 0.2831 l
+0.7824 0.2931 l
+0.7826 0.3044 l
+0.7829 0.3168 l
+0.7832 0.3304 l
+0.7835 0.3450 l
+0.7838 0.3605 l
+0.7841 0.3769 l
+0.7844 0.3940 l
+0.7847 0.4118 l
+0.7849 0.4301 l
+0.7852 0.4489 l
+0.7855 0.4680 l
+0.7858 0.4873 l
+0.7861 0.5068 l
+0.7864 0.5263 l
+0.7867 0.5456 l
+0.7869 0.5648 l
+0.7872 0.5836 l
+0.7875 0.6020 l
+0.7878 0.6199 l
+0.7881 0.6371 l
+0.7884 0.6537 l
+0.7887 0.6694 l
+0.7889 0.6842 l
+0.7892 0.6981 l
+0.7895 0.7109 l
+0.7898 0.7226 l
+0.7901 0.7332 l
+0.7904 0.7425 l
+0.7907 0.7505 l
+0.7909 0.7573 l
+0.7912 0.7627 l
+0.7915 0.7667 l
+0.7918 0.7694 l
+0.7921 0.7706 l
+0.7924 0.7705 l
+0.7927 0.7690 l
+0.7930 0.7662 l
+0.7932 0.7620 l
+0.7935 0.7565 l
+0.7938 0.7497 l
+0.7941 0.7417 l
+0.7944 0.7325 l
+0.7947 0.7222 l
+0.7950 0.7108 l
+0.7952 0.6985 l
+0.7955 0.6852 l
+0.7958 0.6711 l
+0.7961 0.6563 l
+0.7964 0.6408 l
+0.7967 0.6248 l
+0.7970 0.6083 l
+0.7972 0.5914 l
+0.7975 0.5742 l
+0.7978 0.5568 l
+0.7981 0.5394 l
+0.7984 0.5219 l
+0.7987 0.5046 l
+0.7990 0.4875 l
+0.7992 0.4707 l
+0.7995 0.4543 l
+0.7998 0.4383 l
+0.8001 0.4230 l
+0.8004 0.4083 l
+0.8007 0.3944 l
+0.8010 0.3812 l
+0.8013 0.3690 l
+0.8015 0.3577 l
+0.8018 0.3473 l
+0.8021 0.3381 l
+0.8024 0.3300 l
+0.8027 0.3229 l
+0.8030 0.3171 l
+0.8033 0.3125 l
+0.8035 0.3091 l
+0.8038 0.3069 l
+0.8041 0.3060 l
+0.8044 0.3063 l
+0.8047 0.3078 l
+0.8050 0.3105 l
+0.8053 0.3145 l
+0.8055 0.3196 l
+0.8058 0.3258 l
+0.8061 0.3331 l
+0.8064 0.3414 l
+0.8067 0.3507 l
+0.8070 0.3610 l
+0.8073 0.3721 l
+0.8076 0.3840 l
+0.8078 0.3966 l
+0.8081 0.4099 l
+0.8084 0.4237 l
+0.8087 0.4380 l
+0.8090 0.4528 l
+0.8093 0.4678 l
+0.8096 0.4831 l
+0.8098 0.4985 l
+0.8101 0.5140 l
+0.8104 0.5295 l
+0.8107 0.5448 l
+0.8110 0.5599 l
+0.8113 0.5748 l
+0.8116 0.5892 l
+0.8118 0.6033 l
+0.8121 0.6168 l
+0.8124 0.6297 l
+0.8127 0.6419 l
+0.8130 0.6534 l
+0.8133 0.6641 l
+0.8136 0.6740 l
+0.8138 0.6829 l
+0.8141 0.6909 l
+0.8144 0.6980 l
+0.8147 0.7040 l
+0.8150 0.7090 l
+0.8153 0.7129 l
+0.8156 0.7157 l
+0.8159 0.7175 l
+0.8161 0.7181 l
+0.8164 0.7177 l
+0.8167 0.7162 l
+0.8170 0.7136 l
+0.8173 0.7100 l
+0.8176 0.7053 l
+0.8179 0.6997 l
+0.8181 0.6931 l
+0.8184 0.6856 l
+0.8187 0.6773 l
+0.8190 0.6682 l
+0.8193 0.6583 l
+0.8196 0.6477 l
+0.8199 0.6365 l
+0.8201 0.6248 l
+0.8204 0.6126 l
+0.8207 0.5999 l
+0.8210 0.5869 l
+0.8213 0.5737 l
+0.8216 0.5602 l
+0.8219 0.5467 l
+0.8221 0.5331 l
+0.8224 0.5196 l
+0.8227 0.5062 l
+0.8230 0.4929 l
+0.8233 0.4800 l
+0.8236 0.4674 l
+0.8239 0.4551 l
+0.8242 0.4434 l
+0.8244 0.4322 l
+0.8247 0.4216 l
+0.8250 0.4116 l
+0.8253 0.4024 l
+0.8256 0.3939 l
+0.8259 0.3862 l
+0.8262 0.3793 l
+0.8264 0.3733 l
+0.8267 0.3682 l
+0.8270 0.3640 l
+0.8273 0.3607 l
+0.8276 0.3584 l
+0.8279 0.3570 l
+0.8282 0.3566 l
+0.8284 0.3571 l
+0.8287 0.3586 l
+0.8290 0.3610 l
+0.8293 0.3643 l
+0.8296 0.3685 l
+0.8299 0.3735 l
+0.8302 0.3794 l
+0.8304 0.3860 l
+0.8307 0.3934 l
+0.8310 0.4014 l
+0.8313 0.4101 l
+0.8316 0.4194 l
+0.8319 0.4292 l
+0.8322 0.4395 l
+0.8325 0.4502 l
+0.8327 0.4612 l
+0.8330 0.4725 l
+0.8333 0.4841 l
+0.8336 0.4957 l
+0.8339 0.5075 l
+0.8342 0.5193 l
+0.8345 0.5310 l
+0.8347 0.5426 l
+0.8350 0.5541 l
+0.8353 0.5652 l
+0.8356 0.5761 l
+0.8359 0.5866 l
+0.8362 0.5967 l
+0.8365 0.6064 l
+0.8367 0.6155 l
+0.8370 0.6240 l
+0.8373 0.6319 l
+0.8376 0.6391 l
+0.8379 0.6457 l
+0.8382 0.6515 l
+0.8385 0.6566 l
+0.8387 0.6609 l
+0.8390 0.6644 l
+0.8393 0.6671 l
+0.8396 0.6690 l
+0.8399 0.6700 l
+0.8402 0.6702 l
+0.8405 0.6697 l
+0.8408 0.6683 l
+0.8410 0.6661 l
+0.8413 0.6631 l
+0.8416 0.6594 l
+0.8419 0.6549 l
+0.8422 0.6498 l
+0.8425 0.6440 l
+0.8428 0.6375 l
+0.8430 0.6305 l
+0.8433 0.6229 l
+0.8436 0.6149 l
+0.8439 0.6064 l
+0.8442 0.5975 l
+0.8445 0.5882 l
+0.8448 0.5787 l
+0.8450 0.5690 l
+0.8453 0.5590 l
+0.8456 0.5490 l
+0.8459 0.5389 l
+0.8462 0.5288 l
+0.8465 0.5187 l
+0.8468 0.5088 l
+0.8470 0.4990 l
+0.8473 0.4895 l
+0.8476 0.4802 l
+0.8479 0.4712 l
+0.8482 0.4626 l
+0.8485 0.4545 l
+0.8488 0.4467 l
+0.8491 0.4395 l
+0.8493 0.4329 l
+0.8496 0.4267 l
+0.8499 0.4212 l
+0.8502 0.4164 l
+0.8505 0.4121 l
+0.8508 0.4086 l
+0.8511 0.4057 l
+0.8513 0.4035 l
+0.8516 0.4020 l
+0.8519 0.4012 l
+0.8522 0.4011 l
+0.8525 0.4017 l
+0.8528 0.4030 l
+0.8531 0.4050 l
+0.8533 0.4076 l
+0.8536 0.4109 l
+0.8539 0.4148 l
+0.8542 0.4193 l
+0.8545 0.4243 l
+0.8548 0.4299 l
+0.8551 0.4359 l
+0.8553 0.4424 l
+0.8556 0.4494 l
+0.8559 0.4566 l
+0.8562 0.4643 l
+0.8565 0.4722 l
+0.8568 0.4803 l
+0.8571 0.4886 l
+0.8574 0.4971 l
+0.8576 0.5056 l
+0.8579 0.5142 l
+0.8582 0.5228 l
+0.8585 0.5313 l
+0.8588 0.5397 l
+0.8591 0.5480 l
+0.8594 0.5560 l
+0.8596 0.5638 l
+0.8599 0.5714 l
+0.8602 0.5786 l
+0.8605 0.5855 l
+0.8608 0.5919 l
+0.8611 0.5980 l
+0.8614 0.6036 l
+0.8616 0.6086 l
+0.8619 0.6132 l
+0.8622 0.6173 l
+0.8625 0.6208 l
+0.8628 0.6237 l
+0.8631 0.6260 l
+0.8634 0.6278 l
+0.8637 0.6289 l
+0.8639 0.6295 l
+0.8642 0.6295 l
+0.8645 0.6289 l
+0.8648 0.6277 l
+0.8651 0.6259 l
+0.8654 0.6236 l
+0.8657 0.6208 l
+0.8659 0.6174 l
+0.8662 0.6136 l
+0.8665 0.6093 l
+0.8668 0.6045 l
+0.8671 0.5994 l
+0.8674 0.5938 l
+0.8677 0.5880 l
+0.8679 0.5818 l
+0.8682 0.5753 l
+0.8685 0.5687 l
+0.8688 0.5618 l
+0.8691 0.5548 l
+0.8694 0.5477 l
+0.8697 0.5405 l
+0.8699 0.5333 l
+0.8702 0.5261 l
+0.8705 0.5189 l
+0.8708 0.5119 l
+0.8711 0.5050 l
+0.8714 0.4983 l
+0.8717 0.4917 l
+0.8720 0.4854 l
+0.8722 0.4794 l
+0.8725 0.4737 l
+0.8728 0.4684 l
+0.8731 0.4634 l
+0.8734 0.4588 l
+0.8737 0.4546 l
+0.8740 0.4508 l
+0.8742 0.4475 l
+0.8745 0.4447 l
+0.8748 0.4423 l
+0.8751 0.4404 l
+0.8754 0.4390 l
+0.8757 0.4381 l
+0.8760 0.4377 l
+0.8762 0.4378 l
+0.8765 0.4384 l
+0.8768 0.4395 l
+0.8771 0.4410 l
+0.8774 0.4430 l
+0.8777 0.4455 l
+0.8780 0.4483 l
+0.8782 0.4516 l
+0.8785 0.4552 l
+0.8788 0.4593 l
+0.8791 0.4636 l
+0.8794 0.4683 l
+0.8797 0.4732 l
+0.8800 0.4784 l
+0.8803 0.4838 l
+0.8805 0.4893 l
+0.8808 0.4951 l
+0.8811 0.5009 l
+0.8814 0.5068 l
+0.8817 0.5128 l
+0.8820 0.5188 l
+0.8823 0.5248 l
+0.8825 0.5307 l
+0.8828 0.5365 l
+0.8831 0.5422 l
+0.8834 0.5478 l
+0.8837 0.5532 l
+0.8840 0.5583 l
+0.8843 0.5633 l
+0.8845 0.5680 l
+0.8848 0.5724 l
+0.8851 0.5764 l
+0.8854 0.5802 l
+0.8857 0.5836 l
+0.8860 0.5867 l
+0.8863 0.5894 l
+0.8865 0.5916 l
+0.8868 0.5935 l
+0.8871 0.5950 l
+0.8874 0.5961 l
+0.8877 0.5968 l
+0.8880 0.5971 l
+0.8883 0.5969 l
+0.8886 0.5964 l
+0.8888 0.5954 l
+0.8891 0.5941 l
+0.8894 0.5924 l
+0.8897 0.5903 l
+0.8900 0.5879 l
+0.8903 0.5852 l
+0.8906 0.5821 l
+0.8908 0.5787 l
+0.8911 0.5751 l
+0.8914 0.5712 l
+0.8917 0.5672 l
+0.8920 0.5629 l
+0.8923 0.5584 l
+0.8926 0.5538 l
+0.8928 0.5491 l
+0.8931 0.5442 l
+0.8934 0.5394 l
+0.8937 0.5345 l
+0.8940 0.5295 l
+0.8943 0.5246 l
+0.8946 0.5198 l
+0.8948 0.5150 l
+0.8951 0.5104 l
+0.8954 0.5058 l
+0.8957 0.5014 l
+0.8960 0.4972 l
+0.8963 0.4932 l
+0.8966 0.4894 l
+0.8969 0.4858 l
+0.8971 0.4825 l
+0.8974 0.4795 l
+0.8977 0.4767 l
+0.8980 0.4743 l
+0.8983 0.4721 l
+0.8986 0.4703 l
+0.8989 0.4688 l
+0.8991 0.4677 l
+0.8994 0.4668 l
+0.8997 0.4663 l
+0.9000 0.4662 l
+0.9003 0.4663 l
+0.9006 0.4668 l
+0.9009 0.4676 l
+0.9011 0.4688 l
+0.9014 0.4702 l
+0.9017 0.4720 l
+0.9020 0.4740 l
+0.9023 0.4762 l
+0.9026 0.4788 l
+0.9029 0.4816 l
+0.9031 0.4845 l
+0.9034 0.4877 l
+0.9037 0.4911 l
+0.9040 0.4946 l
+0.9043 0.4982 l
+0.9046 0.5020 l
+0.9049 0.5059 l
+0.9052 0.5098 l
+0.9054 0.5138 l
+0.9057 0.5178 l
+0.9060 0.5218 l
+0.9063 0.5257 l
+0.9066 0.5297 l
+0.9069 0.5335 l
+0.9072 0.5373 l
+0.9074 0.5410 l
+0.9077 0.5445 l
+0.9080 0.5479 l
+0.9083 0.5511 l
+0.9086 0.5542 l
+0.9089 0.5570 l
+0.9092 0.5597 l
+0.9094 0.5621 l
+0.9097 0.5643 l
+0.9100 0.5662 l
+0.9103 0.5679 l
+0.9106 0.5694 l
+0.9109 0.5705 l
+0.9112 0.5714 l
+0.9115 0.5721 l
+0.9117 0.5724 l
+0.9120 0.5725 l
+0.9123 0.5723 l
+0.9126 0.5719 l
+0.9129 0.5712 l
+0.9132 0.5702 l
+0.9135 0.5690 l
+0.9137 0.5676 l
+0.9140 0.5659 l
+0.9143 0.5641 l
+0.9146 0.5620 l
+0.9149 0.5597 l
+0.9152 0.5573 l
+0.9155 0.5547 l
+0.9157 0.5520 l
+0.9160 0.5491 l
+0.9163 0.5462 l
+0.9166 0.5431 l
+0.9169 0.5400 l
+0.9172 0.5369 l
+0.9175 0.5337 l
+0.9177 0.5305 l
+0.9180 0.5272 l
+0.9183 0.5241 l
+0.9186 0.5209 l
+0.9189 0.5178 l
+0.9192 0.5148 l
+0.9195 0.5119 l
+0.9198 0.5090 l
+0.9200 0.5063 l
+0.9203 0.5038 l
+0.9206 0.5013 l
+0.9209 0.4991 l
+0.9212 0.4970 l
+0.9215 0.4951 l
+0.9218 0.4934 l
+0.9220 0.4918 l
+0.9223 0.4905 l
+0.9226 0.4894 l
+0.9229 0.4885 l
+0.9232 0.4878 l
+0.9235 0.4873 l
+0.9238 0.4871 l
+0.9240 0.4870 l
+0.9243 0.4872 l
+0.9246 0.4876 l
+0.9249 0.4882 l
+0.9252 0.4890 l
+0.9255 0.4900 l
+0.9258 0.4912 l
+0.9260 0.4925 l
+0.9263 0.4940 l
+0.9266 0.4957 l
+0.9269 0.4975 l
+0.9272 0.4995 l
+0.9275 0.5016 l
+0.9278 0.5038 l
+0.9281 0.5060 l
+0.9283 0.5084 l
+0.9286 0.5108 l
+0.9289 0.5133 l
+0.9292 0.5159 l
+0.9295 0.5184 l
+0.9298 0.5210 l
+0.9301 0.5235 l
+0.9303 0.5260 l
+0.9306 0.5285 l
+0.9309 0.5310 l
+0.9312 0.5334 l
+0.9315 0.5357 l
+0.9318 0.5379 l
+0.9321 0.5400 l
+0.9323 0.5421 l
+0.9326 0.5440 l
+0.9329 0.5457 l
+0.9332 0.5474 l
+0.9335 0.5489 l
+0.9338 0.5502 l
+0.9341 0.5514 l
+0.9343 0.5524 l
+0.9346 0.5533 l
+0.9349 0.5539 l
+0.9352 0.5545 l
+0.9355 0.5548 l
+0.9358 0.5550 l
+0.9361 0.5550 l
+0.9364 0.5548 l
+0.9366 0.5545 l
+0.9369 0.5540 l
+0.9372 0.5533 l
+0.9375 0.5525 l
+0.9378 0.5516 l
+0.9381 0.5505 l
+0.9384 0.5493 l
+0.9386 0.5479 l
+0.9389 0.5465 l
+0.9392 0.5449 l
+0.9395 0.5433 l
+0.9398 0.5415 l
+0.9401 0.5397 l
+0.9404 0.5378 l
+0.9406 0.5359 l
+0.9409 0.5340 l
+0.9412 0.5320 l
+0.9415 0.5300 l
+0.9418 0.5280 l
+0.9421 0.5260 l
+0.9424 0.5240 l
+0.9426 0.5220 l
+0.9429 0.5201 l
+0.9432 0.5182 l
+0.9435 0.5164 l
+0.9438 0.5147 l
+0.9441 0.5130 l
+0.9444 0.5115 l
+0.9447 0.5100 l
+0.9449 0.5086 l
+0.9452 0.5073 l
+0.9455 0.5062 l
+0.9458 0.5052 l
+0.9461 0.5043 l
+0.9464 0.5035 l
+0.9467 0.5028 l
+0.9469 0.5023 l
+0.9472 0.5019 l
+0.9475 0.5017 l
+0.9478 0.5016 l
+0.9481 0.5016 l
+0.9484 0.5017 l
+0.9487 0.5020 l
+0.9489 0.5024 l
+0.9492 0.5029 l
+0.9495 0.5036 l
+0.9498 0.5044 l
+0.9501 0.5052 l
+0.9504 0.5062 l
+0.9507 0.5072 l
+0.9509 0.5084 l
+0.9512 0.5096 l
+0.9515 0.5109 l
+0.9518 0.5123 l
+0.9521 0.5137 l
+0.9524 0.5152 l
+0.9527 0.5167 l
+0.9530 0.5182 l
+0.9532 0.5198 l
+0.9535 0.5213 l
+0.9538 0.5229 l
+0.9541 0.5244 l
+0.9544 0.5260 l
+0.9547 0.5275 l
+0.9550 0.5290 l
+0.9552 0.5304 l
+0.9555 0.5318 l
+0.9558 0.5331 l
+0.9561 0.5344 l
+0.9564 0.5356 l
+0.9567 0.5368 l
+0.9570 0.5378 l
+0.9572 0.5388 l
+0.9575 0.5397 l
+0.9578 0.5404 l
+0.9581 0.5411 l
+0.9584 0.5417 l
+0.9587 0.5422 l
+0.9590 0.5426 l
+0.9592 0.5429 l
+0.9595 0.5431 l
+0.9598 0.5431 l
+0.9601 0.5431 l
+0.9604 0.5430 l
+0.9607 0.5427 l
+0.9610 0.5424 l
+0.9613 0.5420 l
+0.9615 0.5415 l
+0.9618 0.5409 l
+0.9621 0.5402 l
+0.9624 0.5394 l
+0.9627 0.5386 l
+0.9630 0.5377 l
+0.9633 0.5367 l
+0.9635 0.5357 l
+0.9638 0.5347 l
+0.9641 0.5336 l
+0.9644 0.5324 l
+0.9647 0.5313 l
+0.9650 0.5301 l
+0.9653 0.5289 l
+0.9655 0.5277 l
+0.9658 0.5265 l
+0.9661 0.5253 l
+0.9664 0.5241 l
+0.9667 0.5230 l
+0.9670 0.5218 l
+0.9673 0.5207 l
+0.9676 0.5197 l
+0.9678 0.5186 l
+0.9681 0.5177 l
+0.9684 0.5167 l
+0.9687 0.5159 l
+0.9690 0.5151 l
+0.9693 0.5144 l
+0.9696 0.5137 l
+0.9698 0.5131 l
+0.9701 0.5126 l
+0.9704 0.5121 l
+0.9707 0.5118 l
+0.9710 0.5115 l
+0.9713 0.5113 l
+0.9716 0.5112 l
+0.9718 0.5111 l
+0.9721 0.5112 l
+0.9724 0.5113 l
+0.9727 0.5115 l
+0.9730 0.5117 l
+0.9733 0.5121 l
+0.9736 0.5125 l
+0.9738 0.5129 l
+0.9741 0.5135 l
+0.9744 0.5141 l
+0.9747 0.5147 l
+0.9750 0.5154 l
+0.9753 0.5161 l
+0.9756 0.5169 l
+0.9759 0.5177 l
+0.9761 0.5186 l
+0.9764 0.5194 l
+0.9767 0.5203 l
+0.9770 0.5212 l
+0.9773 0.5221 l
+0.9776 0.5230 l
+0.9779 0.5240 l
+0.9781 0.5249 l
+0.9784 0.5258 l
+0.9787 0.5266 l
+0.9790 0.5275 l
+0.9793 0.5283 l
+0.9796 0.5291 l
+0.9799 0.5299 l
+0.9801 0.5306 l
+0.9804 0.5313 l
+0.9807 0.5320 l
+0.9810 0.5326 l
+0.9813 0.5331 l
+0.9816 0.5336 l
+0.9819 0.5341 l
+0.9821 0.5344 l
+0.9824 0.5348 l
+0.9827 0.5350 l
+0.9830 0.5352 l
+0.9833 0.5354 l
+0.9836 0.5355 l
+0.9839 0.5355 l
+0.9842 0.5354 l
+0.9844 0.5353 l
+0.9847 0.5352 l
+0.9850 0.5350 l
+0.9853 0.5347 l
+0.9856 0.5344 l
+0.9859 0.5341 l
+0.9862 0.5336 l
+0.9864 0.5332 l
+0.9867 0.5327 l
+0.9870 0.5322 l
+0.9873 0.5316 l
+0.9876 0.5310 l
+0.9879 0.5304 l
+0.9882 0.5298 l
+0.9884 0.5291 l
+0.9887 0.5284 l
+0.9890 0.5278 l
+0.9893 0.5271 l
+0.9896 0.5264 l
+0.9899 0.5257 l
+0.9902 0.5250 l
+0.9904 0.5243 l
+0.9907 0.5237 l
+0.9910 0.5230 l
+0.9913 0.5224 l
+0.9916 0.5218 l
+0.9919 0.5212 l
+0.9922 0.5207 l
+0.9925 0.5202 l
+0.9927 0.5197 l
+0.9930 0.5193 l
+0.9933 0.5189 l
+0.9936 0.5185 l
+0.9939 0.5182 l
+0.9942 0.5179 l
+0.9945 0.5177 l
+0.9947 0.5175 l
+0.9950 0.5173 l
+0.9953 0.5172 l
+0.9956 0.5172 l
+0.9959 0.5172 l
+0.9962 0.5172 l
+0.9965 0.5173 l
+0.9967 0.5174 l
+0.9970 0.5176 l
+0.9973 0.5178 l
+0.9976 0.5180 l
+0.9979 0.5183 l
+0.9982 0.5186 l
+0.9985 0.5189 l
+0.9987 0.5193 l
+0.9990 0.5197 l
+0.9993 0.5201 l
+0.9996 0.5206 l
+0.9999 0.5210 l
+1.0002 0.5215 l
+1.0005 0.5220 l
+1.0008 0.5225 l
+1.0010 0.5230 l
+1.0013 0.5235 l
+1.0016 0.5240 l
+1.0019 0.5245 l
+1.0022 0.5250 l
+1.0025 0.5255 l
+1.0028 0.5260 l
+1.0030 0.5265 l
+1.0033 0.5270 l
+1.0036 0.5274 l
+1.0039 0.5278 l
+1.0042 0.5282 l
+1.0045 0.5286 l
+1.0048 0.5290 l
+1.0050 0.5293 l
+1.0053 0.5296 l
+1.0056 0.5298 l
+1.0059 0.5301 l
+1.0062 0.5303 l
+1.0065 0.5305 l
+1.0068 0.5306 l
+1.0070 0.5307 l
+1.0073 0.5308 l
+1.0076 0.5308 l
+1.0079 0.5308 l
+1.0082 0.5308 l
+1.0085 0.5307 l
+1.0088 0.5306 l
+1.0091 0.5305 l
+1.0093 0.5303 l
+1.0096 0.5302 l
+1.0099 0.5299 l
+1.0102 0.5297 l
+1.0105 0.5295 l
+1.0108 0.5292 l
+1.0111 0.5289 l
+1.0113 0.5286 l
+1.0116 0.5282 l
+1.0119 0.5279 l
+1.0122 0.5275 l
+1.0125 0.5272 l
+1.0128 0.5268 l
+1.0131 0.5264 l
+1.0133 0.5261 l
+1.0136 0.5257 l
+1.0139 0.5253 l
+1.0142 0.5249 l
+1.0145 0.5246 l
+1.0148 0.5242 l
+1.0151 0.5239 l
+1.0153 0.5235 l
+1.0156 0.5232 l
+1.0159 0.5229 l
+1.0162 0.5226 l
+1.0165 0.5223 l
+1.0168 0.5221 l
+1.0171 0.5218 l
+1.0174 0.5216 l
+1.0176 0.5214 l
+1.0179 0.5213 l
+1.0182 0.5211 l
+1.0185 0.5210 l
+1.0188 0.5209 l
+1.0191 0.5208 l
+1.0194 0.5208 l
+1.0196 0.5208 l
+1.0199 0.5208 l
+1.0202 0.5208 l
+1.0205 0.5208 l
+1.0208 0.5209 l
+1.0211 0.5210 l
+1.0214 0.5211 l
+1.0216 0.5213 l
+1.0219 0.5214 l
+1.0222 0.5216 l
+1.0225 0.5218 l
+1.0228 0.5220 l
+1.0231 0.5222 l
+1.0234 0.5224 l
+1.0237 0.5227 l
+1.0239 0.5229 l
+1.0242 0.5232 l
+1.0245 0.5234 l
+1.0248 0.5237 l
+1.0251 0.5240 l
+1.0254 0.5243 l
+1.0257 0.5245 l
+1.0259 0.5248 l
+1.0262 0.5251 l
+1.0265 0.5253 l
+1.0268 0.5256 l
+1.0271 0.5259 l
+1.0274 0.5261 l
+1.0277 0.5263 l
+1.0279 0.5266 l
+1.0282 0.5268 l
+1.0285 0.5270 l
+1.0288 0.5272 l
+1.0291 0.5273 l
+1.0294 0.5275 l
+1.0297 0.5276 l
+1.0299 0.5277 l
+1.0302 0.5278 l
+1.0305 0.5279 l
+1.0308 0.5280 l
+1.0311 0.5280 l
+1.0314 0.5281 l
+1.0317 0.5281 l
+1.0320 0.5281 l
+1.0322 0.5280 l
+1.0325 0.5280 l
+1.0328 0.5280 l
+1.0331 0.5279 l
+1.0334 0.5278 l
+1.0337 0.5277 l
+1.0340 0.5276 l
+1.0342 0.5275 l
+1.0345 0.5273 l
+1.0348 0.5272 l
+1.0351 0.5270 l
+1.0354 0.5268 l
+1.0357 0.5267 l
+1.0360 0.5265 l
+1.0362 0.5263 l
+1.0365 0.5261 l
+1.0368 0.5259 l
+1.0371 0.5257 l
+1.0374 0.5255 l
+1.0377 0.5253 l
+1.0380 0.5251 l
+1.0382 0.5249 l
+1.0385 0.5247 l
+1.0388 0.5245 l
+1.0391 0.5244 l
+1.0394 0.5242 l
+1.0397 0.5240 l
+1.0400 0.5239 l
+1.0403 0.5237 l
+1.0405 0.5236 l
+1.0408 0.5234 l
+1.0411 0.5233 l
+1.0414 0.5232 l
+1.0417 0.5231 l
+1.0420 0.5230 l
+1.0423 0.5230 l
+1.0425 0.5229 l
+1.0428 0.5229 l
+1.0431 0.5228 l
+1.0434 0.5228 l
+1.0437 0.5228 l
+1.0440 0.5228 l
+1.0443 0.5228 l
+1.0445 0.5229 l
+1.0448 0.5229 l
+1.0451 0.5229 l
+1.0454 0.5230 l
+1.0457 0.5231 l
+1.0460 0.5232 l
+1.0463 0.5233 l
+1.0465 0.5234 l
+1.0468 0.5235 l
+1.0471 0.5236 l
+1.0474 0.5237 l
+1.0477 0.5238 l
+1.0480 0.5240 l
+1.0483 0.5241 l
+1.0486 0.5242 l
+1.0488 0.5244 l
+1.0491 0.5245 l
+1.0494 0.5247 l
+1.0497 0.5248 l
+1.0500 0.5249 l
+1.0503 0.5251 l
+1.0506 0.5252 l
+1.0508 0.5253 l
+1.0511 0.5255 l
+1.0514 0.5256 l
+1.0517 0.5257 l
+1.0520 0.5258 l
+1.0523 0.5259 l
+1.0526 0.5260 l
+1.0528 0.5261 l
+1.0531 0.5262 l
+1.0534 0.5263 l
+1.0537 0.5263 l
+1.0540 0.5264 l
+1.0543 0.5264 l
+1.0546 0.5265 l
+1.0548 0.5265 l
+1.0551 0.5265 l
+1.0554 0.5266 l
+1.0557 0.5266 l
+1.0560 0.5266 l
+1.0563 0.5265 l
+1.0566 0.5265 l
+1.0569 0.5265 l
+1.0571 0.5264 l
+1.0574 0.5264 l
+1.0577 0.5263 l
+1.0580 0.5263 l
+1.0583 0.5262 l
+1.0586 0.5262 l
+1.0589 0.5261 l
+1.0591 0.5260 l
+1.0594 0.5259 l
+1.0597 0.5258 l
+1.0600 0.5257 l
+1.0603 0.5256 l
+1.0606 0.5255 l
+1.0609 0.5254 l
+1.0611 0.5253 l
+1.0614 0.5252 l
+1.0617 0.5251 l
+1.0620 0.5250 l
+1.0623 0.5249 l
+1.0626 0.5248 l
+1.0629 0.5248 l
+1.0631 0.5247 l
+1.0634 0.5246 l
+1.0637 0.5245 l
+1.0640 0.5244 l
+1.0643 0.5243 l
+1.0646 0.5243 l
+1.0649 0.5242 l
+1.0652 0.5242 l
+1.0654 0.5241 l
+1.0657 0.5241 l
+1.0660 0.5240 l
+1.0663 0.5240 l
+1.0666 0.5240 l
+1.0669 0.5239 l
+1.0672 0.5239 l
+1.0674 0.5239 l
+1.0677 0.5239 l
+1.0680 0.5239 l
+1.0683 0.5239 l
+1.0686 0.5239 l
+1.0689 0.5240 l
+1.0692 0.5240 l
+1.0694 0.5240 l
+1.0697 0.5241 l
+1.0700 0.5241 l
+1.0703 0.5242 l
+1.0706 0.5242 l
+1.0709 0.5243 l
+1.0712 0.5243 l
+1.0715 0.5244 l
+1.0717 0.5244 l
+1.0720 0.5245 l
+1.0723 0.5246 l
+1.0726 0.5246 l
+1.0729 0.5247 l
+1.0732 0.5248 l
+1.0735 0.5248 l
+1.0737 0.5249 l
+1.0740 0.5250 l
+1.0743 0.5251 l
+1.0746 0.5251 l
+1.0749 0.5252 l
+1.0752 0.5252 l
+1.0755 0.5253 l
+1.0757 0.5254 l
+1.0760 0.5254 l
+1.0763 0.5255 l
+1.0766 0.5255 l
+1.0769 0.5256 l
+1.0772 0.5256 l
+1.0775 0.5256 l
+1.0777 0.5257 l
+1.0780 0.5257 l
+1.0783 0.5257 l
+1.0786 0.5257 l
+1.0789 0.5257 l
+1.0792 0.5258 l
+1.0795 0.5258 l
+1.0798 0.5258 l
+1.0800 0.5258 l
+1.0803 0.5257 l
+1.0806 0.5257 l
+1.0809 0.5257 l
+1.0812 0.5257 l
+1.0815 0.5257 l
+1.0818 0.5256 l
+1.0820 0.5256 l
+1.0823 0.5256 l
+1.0826 0.5255 l
+1.0829 0.5255 l
+1.0832 0.5255 l
+1.0835 0.5254 l
+1.0838 0.5254 l
+1.0840 0.5253 l
+1.0843 0.5253 l
+1.0846 0.5252 l
+1.0849 0.5252 l
+1.0852 0.5251 l
+1.0855 0.5251 l
+1.0858 0.5251 l
+1.0860 0.5250 l
+1.0863 0.5250 l
+1.0866 0.5249 l
+1.0869 0.5249 l
+1.0872 0.5248 l
+1.0875 0.5248 l
+1.0878 0.5247 l
+1.0881 0.5247 l
+1.0883 0.5247 l
+1.0886 0.5246 l
+1.0889 0.5246 l
+1.0892 0.5246 l
+1.0895 0.5246 l
+1.0898 0.5245 l
+1.0901 0.5245 l
+1.0903 0.5245 l
+1.0906 0.5245 l
+1.0909 0.5245 l
+1.0912 0.5245 l
+1.0915 0.5245 l
+1.0918 0.5245 l
+1.0921 0.5245 l
+1.0923 0.5245 l
+1.0926 0.5245 l
+1.0929 0.5245 l
+1.0932 0.5245 l
+1.0935 0.5245 l
+1.0938 0.5246 l
+1.0941 0.5246 l
+1.0943 0.5246 l
+1.0946 0.5246 l
+1.0949 0.5247 l
+1.0952 0.5247 l
+1.0955 0.5247 l
+1.0958 0.5247 l
+1.0961 0.5248 l
+1.0964 0.5248 l
+1.0966 0.5248 l
+1.0969 0.5249 l
+1.0972 0.5249 l
+1.0975 0.5249 l
+1.0978 0.5250 l
+1.0981 0.5250 l
+1.0984 0.5250 l
+1.0986 0.5251 l
+1.0989 0.5251 l
+1.0992 0.5251 l
+1.0995 0.5251 l
+1.0998 0.5252 l
+1.1001 0.5252 l
+1.1004 0.5252 l
+1.1006 0.5252 l
+1.1009 0.5253 l
+1.1012 0.5253 l
+1.1015 0.5253 l
+1.1018 0.5253 l
+1.1021 0.5253 l
+1.1024 0.5253 l
+1.1026 0.5253 l
+1.1029 0.5253 l
+1.1032 0.5253 l
+1.1035 0.5254 l
+1.1038 0.5254 l
+1.1041 0.5253 l
+1.1044 0.5253 l
+1.1047 0.5253 l
+1.1049 0.5253 l
+1.1052 0.5253 l
+1.1055 0.5253 l
+1.1058 0.5253 l
+1.1061 0.5253 l
+1.1064 0.5253 l
+1.1067 0.5252 l
+1.1069 0.5252 l
+1.1072 0.5252 l
+1.1075 0.5252 l
+1.1078 0.5252 l
+1.1081 0.5252 l
+1.1084 0.5251 l
+1.1087 0.5251 l
+1.1089 0.5251 l
+1.1092 0.5251 l
+1.1095 0.5250 l
+1.1098 0.5250 l
+1.1101 0.5250 l
+1.1104 0.5250 l
+1.1107 0.5250 l
+1.1109 0.5249 l
+1.1112 0.5249 l
+1.1115 0.5249 l
+1.1118 0.5249 l
+1.1121 0.5249 l
+1.1124 0.5248 l
+1.1127 0.5248 l
+1.1130 0.5248 l
+1.1132 0.5248 l
+1.1135 0.5248 l
+1.1138 0.5248 l
+1.1141 0.5248 l
+1.1144 0.5248 l
+1.1147 0.5248 l
+1.1150 0.5248 l
+1.1152 0.5248 l
+1.1155 0.5248 l
+1.1158 0.5248 l
+1.1161 0.5248 l
+1.1164 0.5248 l
+1.1167 0.5248 l
+1.1170 0.5248 l
+1.1172 0.5248 l
+1.1175 0.5248 l
+1.1178 0.5248 l
+1.1181 0.5248 l
+1.1184 0.5248 l
+1.1187 0.5248 l
+1.1190 0.5248 l
+1.1192 0.5249 l
+1.1195 0.5249 l
+1.1198 0.5249 l
+1.1201 0.5249 l
+1.1204 0.5249 l
+1.1207 0.5249 l
+1.1210 0.5249 l
+1.1213 0.5250 l
+1.1215 0.5250 l
+1.1218 0.5250 l
+1.1221 0.5250 l
+1.1224 0.5250 l
+1.1227 0.5250 l
+1.1230 0.5250 l
+1.1233 0.5251 l
+1.1235 0.5251 l
+1.1238 0.5251 l
+1.1241 0.5251 l
+1.1244 0.5251 l
+1.1247 0.5251 l
+1.1250 0.5251 l
+1.1253 0.5251 l
+1.1255 0.5251 l
+1.1258 0.5251 l
+1.1261 0.5251 l
+1.1264 0.5251 l
+1.1267 0.5252 l
+1.1270 0.5252 l
+1.1273 0.5252 l
+1.1276 0.5252 l
+1.1278 0.5252 l
+1.1281 0.5252 l
+1.1284 0.5252 l
+1.1287 0.5251 l
+1.1290 0.5251 l
+1.1293 0.5251 l
+1.1296 0.5251 l
+1.1298 0.5251 l
+1.1301 0.5251 l
+1.1304 0.5251 l
+1.1307 0.5251 l
+1.1310 0.5251 l
+1.1313 0.5251 l
+1.1316 0.5251 l
+1.1318 0.5251 l
+1.1321 0.5251 l
+1.1324 0.5251 l
+1.1327 0.5250 l
+1.1330 0.5250 l
+1.1333 0.5250 l
+1.1336 0.5250 l
+1.1338 0.5250 l
+1.1341 0.5250 l
+1.1344 0.5250 l
+1.1347 0.5250 l
+1.1350 0.5250 l
+1.1353 0.5250 l
+1.1356 0.5250 l
+1.1359 0.5249 l
+1.1361 0.5249 l
+1.1364 0.5249 l
+1.1367 0.5249 l
+1.1370 0.5249 l
+1.1373 0.5249 l
+1.1376 0.5249 l
+1.1379 0.5249 l
+1.1381 0.5249 l
+1.1384 0.5249 l
+1.1387 0.5249 l
+1.1390 0.5249 l
+1.1393 0.5249 l
+1.1396 0.5249 l
+1.1399 0.5249 l
+1.1401 0.5249 l
+1.1404 0.5249 l
+1.1407 0.5249 l
+1.1410 0.5249 l
+1.1413 0.5249 l
+1.1416 0.5249 l
+1.1419 0.5249 l
+1.1421 0.5249 l
+1.1424 0.5249 l
+1.1427 0.5249 l
+1.1430 0.5249 l
+1.1433 0.5249 l
+1.1436 0.5249 l
+1.1439 0.5250 l
+1.1442 0.5250 l
+1.1444 0.5250 l
+1.1447 0.5250 l
+1.1450 0.5250 l
+1.1453 0.5250 l
+1.1456 0.5250 l
+1.1459 0.5250 l
+1.1462 0.5250 l
+1.1464 0.5250 l
+1.1467 0.5250 l
+1.1470 0.5250 l
+1.1473 0.5250 l
+1.1476 0.5250 l
+1.1479 0.5250 l
+1.1482 0.5250 l
+1.1484 0.5250 l
+1.1487 0.5250 l
+1.1490 0.5251 l
+1.1493 0.5251 l
+1.1496 0.5251 l
+1.1499 0.5251 l
+1.1502 0.5251 l
+1.1504 0.5251 l
+1.1507 0.5251 l
+1.1510 0.5251 l
+1.1513 0.5251 l
+1.1516 0.5251 l
+1.1519 0.5251 l
+1.1522 0.5251 l
+1.1525 0.5251 l
+1.1527 0.5251 l
+1.1530 0.5251 l
+1.1533 0.5251 l
+1.1536 0.5251 l
+1.1539 0.5251 l
+1.1542 0.5251 l
+1.1545 0.5250 l
+1.1547 0.5250 l
+1.1550 0.5250 l
+1.1553 0.5250 l
+1.1556 0.5250 l
+1.1559 0.5250 l
+1.1562 0.5250 l
+1.1565 0.5250 l
+1.1567 0.5250 l
+1.1570 0.5250 l
+1.1573 0.5250 l
+1.1576 0.5250 l
+1.1579 0.5250 l
+1.1582 0.5250 l
+1.1585 0.5250 l
+1.1587 0.5250 l
+1.1590 0.5250 l
+1.1593 0.5250 l
+1.1596 0.5250 l
+1.1599 0.5250 l
+1.1602 0.5250 l
+1.1605 0.5250 l
+1.1608 0.5250 l
+1.1610 0.5250 l
+1.1613 0.5250 l
+1.1616 0.5250 l
+1.1619 0.5250 l
+1.1622 0.5250 l
+1.1625 0.5250 l
+1.1628 0.5250 l
+1.1630 0.5250 l
+1.1633 0.5250 l
+1.1636 0.5250 l
+1.1639 0.5250 l
+1.1642 0.5250 l
+1.1645 0.5250 l
+1.1648 0.5250 l
+1.1650 0.5250 l
+1.1653 0.5250 l
+1.1656 0.5250 l
+1.1659 0.5250 l
+1.1662 0.5250 l
+1.1665 0.5250 l
+1.1668 0.5250 l
+1.1670 0.5250 l
+1.1673 0.5250 l
+1.1676 0.5250 l
+1.1679 0.5250 l
+1.1682 0.5250 l
+1.1685 0.5250 l
+1.1688 0.5250 l
+1.1691 0.5250 l
+1.1693 0.5250 l
+1.1696 0.5250 l
+1.1699 0.5250 l
+1.1702 0.5250 l
+1.1705 0.5250 l
+1.1708 0.5250 l
+1.1711 0.5250 l
+1.1713 0.5250 l
+1.1716 0.5250 l
+1.1719 0.5250 l
+1.1722 0.5250 l
+1.1725 0.5250 l
+1.1728 0.5250 l
+1.1731 0.5250 l
+1.1733 0.5250 l
+1.1736 0.5250 l
+1.1739 0.5250 l
+1.1742 0.5250 l
+1.1745 0.5250 l
+1.1748 0.5250 l
+1.1751 0.5250 l
+1.1754 0.5250 l
+1.1756 0.5250 l
+1.1759 0.5250 l
+1.1762 0.5250 l
+1.1765 0.5250 l
+1.1768 0.5250 l
+1.1771 0.5250 l
+1.1774 0.5250 l
+1.1776 0.5250 l
+1.1779 0.5250 l
+1.1782 0.5250 l
+1.1785 0.5250 l
+1.1788 0.5250 l
+1.1791 0.5250 l
+1.1794 0.5250 l
+1.1796 0.5250 l
+1.1799 0.5250 l
+1.1802 0.5250 l
+1.1805 0.5250 l
+1.1808 0.5250 l
+1.1811 0.5250 l
+1.1814 0.5250 l
+1.1816 0.5250 l
+1.1819 0.5250 l
+1.1822 0.5250 l
+1.1825 0.5250 l
+1.1828 0.5250 l
+1.1831 0.5250 l
+1.1834 0.5250 l
+1.1837 0.5250 l
+1.1839 0.5250 l
+1.1842 0.5250 l
+1.1845 0.5250 l
+1.1848 0.5250 l
+1.1851 0.5250 l
+1.1854 0.5250 l
+1.1857 0.5250 l
+1.1859 0.5250 l
+1.1862 0.5250 l
+1.1865 0.5250 l
+1.1868 0.5250 l
+1.1871 0.5250 l
+1.1874 0.5250 l
+1.1877 0.5250 l
+1.1879 0.5250 l
+1.1882 0.5250 l
+1.1885 0.5250 l
+1.1888 0.5250 l
+1.1891 0.5250 l
+1.1894 0.5250 l
+1.1897 0.5250 l
+1.1899 0.5250 l
+1.1902 0.5250 l
+1.1905 0.5250 l
+1.1908 0.5250 l
+1.1911 0.5250 l
+1.1914 0.5250 l
+1.1917 0.5250 l
+1.1920 0.5250 l
+1.1922 0.5250 l
+1.1925 0.5250 l
+1.1928 0.5250 l
+1.1931 0.5250 l
+1.1934 0.5250 l
+1.1937 0.5250 l
+1.1940 0.5250 l
+1.1942 0.5250 l
+1.1945 0.5250 l
+1.1948 0.5250 l
+1.1951 0.5250 l
+1.1954 0.5250 l
+1.1957 0.5250 l
+1.1960 0.5250 l
+1.1962 0.5250 l
+1.1965 0.5250 l
+1.1968 0.5250 l
+1.1971 0.5250 l
+1.1974 0.5250 l
+1.1977 0.5250 l
+1.1980 0.5250 l
+1.1982 0.5250 l
+1.1985 0.5250 l
+1.1988 0.5250 l
+1.1991 0.5250 l
+1.1994 0.5250 l
+1.1997 0.5250 l
+1.2000 0.5250 l
+1.2003 0.5250 l
+1.2005 0.5250 l
+1.2008 0.5250 l
+1.2011 0.5250 l
+1.2014 0.5250 l
+1.2017 0.5250 l
+1.2020 0.5250 l
+1.2023 0.5250 l
+1.2025 0.5250 l
+1.2028 0.5250 l
+1.2031 0.5250 l
+1.2034 0.5250 l
+1.2037 0.5250 l
+1.2040 0.5250 l
+1.2043 0.5250 l
+1.2045 0.5250 l
+1.2048 0.5250 l
+1.2051 0.5250 l
+1.2054 0.5250 l
+1.2057 0.5250 l
+1.2060 0.5250 l
+1.2063 0.5250 l
+1.2065 0.5250 l
+1.2068 0.5250 l
+1.2071 0.5250 l
+1.2074 0.5250 l
+1.2077 0.5250 l
+1.2080 0.5250 l
+1.2083 0.5250 l
+1.2086 0.5250 l
+1.2088 0.5250 l
+1.2091 0.5250 l
+1.2094 0.5250 l
+1.2097 0.5250 l
+1.2100 0.5250 l
+1.2103 0.5250 l
+1.2106 0.5250 l
+1.2108 0.5250 l
+1.2111 0.5250 l
+1.2114 0.5250 l
+1.2117 0.5250 l
+1.2120 0.5250 l
+1.2123 0.5250 l
+1.2126 0.5250 l
+1.2128 0.5250 l
+1.2131 0.5250 l
+1.2134 0.5250 l
+1.2137 0.5250 l
+1.2140 0.5250 l
+1.2143 0.5250 l
+1.2146 0.5250 l
+1.2148 0.5250 l
+1.2151 0.5250 l
+1.2154 0.5250 l
+1.2157 0.5250 l
+1.2160 0.5250 l
+1.2163 0.5250 l
+1.2166 0.5250 l
+1.2169 0.5250 l
+1.2171 0.5250 l
+1.2174 0.5250 l
+1.2177 0.5250 l
+1.2180 0.5250 l
+1.2183 0.5250 l
+1.2186 0.5250 l
+1.2189 0.5250 l
+1.2191 0.5250 l
+1.2194 0.5250 l
+1.2197 0.5250 l
+1.2200 0.5250 l
+1.2203 0.5250 l
+1.2206 0.5250 l
+1.2209 0.5250 l
+1.2211 0.5250 l
+1.2214 0.5250 l
+1.2217 0.5250 l
+1.2220 0.5250 l
+1.2223 0.5250 l
+1.2226 0.5250 l
+1.2229 0.5250 l
+1.2231 0.5250 l
+1.2234 0.5250 l
+1.2237 0.5250 l
+1.2240 0.5250 l
+1.2243 0.5250 l
+1.2246 0.5250 l
+1.2249 0.5250 l
+1.2252 0.5250 l
+1.2254 0.5250 l
+1.2257 0.5250 l
+1.2260 0.5250 l
+1.2263 0.5250 l
+1.2266 0.5250 l
+1.2269 0.5250 l
+1.2272 0.5250 l
+1.2274 0.5250 l
+1.2277 0.5250 l
+1.2280 0.5250 l
+1.2283 0.5250 l
+1.2286 0.5250 l
+1.2289 0.5250 l
+1.2292 0.5250 l
+1.2294 0.5250 l
+1.2297 0.5250 l
+1.2300 0.5250 l
+1.2303 0.5250 l
+1.2306 0.5250 l
+1.2309 0.5250 l
+1.2312 0.5250 l
+1.2315 0.5250 l
+1.2317 0.5250 l
+1.2320 0.5250 l
+1.2323 0.5250 l
+1.2326 0.5250 l
+1.2329 0.5250 l
+1.2332 0.5250 l
+1.2335 0.5250 l
+1.2337 0.5250 l
+1.2340 0.5250 l
+1.2343 0.5250 l
+1.2346 0.5250 l
+1.2349 0.5250 l
+1.2352 0.5250 l
+1.2355 0.5250 l
+1.2357 0.5250 l
+1.2360 0.5250 l
+1.2363 0.5250 l
+1.2366 0.5250 l
+1.2369 0.5250 l
+1.2372 0.5250 l
+1.2375 0.5250 l
+1.2377 0.5250 l
+1.2380 0.5250 l
+1.2383 0.5250 l
+1.2386 0.5250 l
+1.2389 0.5250 l
+1.2392 0.5250 l
+1.2395 0.5250 l
+1.2398 0.5250 l
+1.2400 0.5250 l
+1.2403 0.5250 l
+1.2406 0.5250 l
+1.2409 0.5250 l
+1.2412 0.5250 l
+1.2415 0.5250 l
+1.2418 0.5250 l
+1.2420 0.5250 l
+1.2423 0.5250 l
+1.2426 0.5250 l
+1.2429 0.5250 l
+1.2432 0.5250 l
+1.2435 0.5250 l
+1.2438 0.5250 l
+1.2440 0.5250 l
+1.2443 0.5250 l
+1.2446 0.5250 l
+1.2449 0.5250 l
+s
+n
+0.1000 0.1000 m
+1.2449 0.1000 l
+s
+n
+0.1000 0.9500 m
+1.2449 0.9500 l
+s
+n
+0.2431 0.1000 m
+0.2431 0.1100 l
+s
+n
+0.2431 0.9500 m
+0.2431 0.9400 l
+s
+n
+0.5293 0.1000 m
+0.5293 0.1100 l
+s
+n
+0.5293 0.9500 m
+0.5293 0.9400 l
+s
+n
+0.8156 0.1000 m
+0.8156 0.1100 l
+s
+n
+0.8156 0.9500 m
+0.8156 0.9400 l
+s
+n
+1.1018 0.1000 m
+1.1018 0.1100 l
+s
+n
+1.1018 0.9500 m
+1.1018 0.9400 l
+s
+n
+0.1000 0.1000 m
+0.1000 0.1200 l
+s
+n
+0.1000 0.9500 m
+0.1000 0.9300 l
+s
+n
+0.3862 0.1000 m
+0.3862 0.1200 l
+s
+n
+0.3862 0.9500 m
+0.3862 0.9300 l
+s
+n
+0.6725 0.1000 m
+0.6725 0.1200 l
+s
+n
+0.6725 0.9500 m
+0.6725 0.9300 l
+s
+n
+0.9587 0.1000 m
+0.9587 0.1200 l
+s
+n
+0.9587 0.9500 m
+0.9587 0.9300 l
+s
+n
+1.2449 0.1000 m
+1.2449 0.1200 l
+s
+n
+1.2449 0.9500 m
+1.2449 0.9300 l
+s
+/Helvetica findfont
+dup length dict begin
+ {1 index /FID ne {def} {pop pop} ifelse} forall
+ /Encoding DefEncoding def
+ currentdict
+end
+/Font4 exch definefont pop
+/Font4 FFSF
+0.0912 0.0653 m
+GS
+[0.0350 0.0000 0.0000 0.0350 0 0] CC
+(0) show
+GR
+/Font4 FFSF
+0.3627 0.0653 m
+GS
+[0.0350 0.0000 0.0000 0.0350 0 0] CC
+(0.5) show
+GR
+/Font4 FFSF
+0.6664 0.0653 m
+GS
+[0.0350 0.0000 0.0000 0.0350 0 0] CC
+(1) show
+GR
+/Font4 FFSF
+0.9351 0.0653 m
+GS
+[0.0350 0.0000 0.0000 0.0350 0 0] CC
+(1.5) show
+GR
+/Font4 FFSF
+1.2359 0.0653 m
+GS
+[0.0350 0.0000 0.0000 0.0350 0 0] CC
+(2) show
+GR
+/Font4 FFSF
+0.5854 0.0239 m
+GS
+[0.0420 0.0000 0.0000 0.0420 0 0] CC
+(Time \(ps\)) show
+GR
+n
+0.1000 0.1000 m
+0.1000 0.9500 l
+s
+n
+1.2449 0.1000 m
+1.2449 0.9500 l
+s
+n
+0.1000 0.2063 m
+0.1100 0.2063 l
+s
+n
+1.2449 0.2063 m
+1.2349 0.2063 l
+s
+n
+0.1000 0.4188 m
+0.1100 0.4188 l
+s
+n
+1.2449 0.4188 m
+1.2349 0.4188 l
+s
+n
+0.1000 0.6312 m
+0.1100 0.6312 l
+s
+n
+1.2449 0.6312 m
+1.2349 0.6312 l
+s
+n
+0.1000 0.8438 m
+0.1100 0.8438 l
+s
+n
+1.2449 0.8438 m
+1.2349 0.8438 l
+s
+n
+0.1000 0.1000 m
+0.1200 0.1000 l
+s
+n
+1.2449 0.1000 m
+1.2249 0.1000 l
+s
+n
+0.1000 0.3125 m
+0.1200 0.3125 l
+s
+n
+1.2449 0.3125 m
+1.2249 0.3125 l
+s
+n
+0.1000 0.5250 m
+0.1200 0.5250 l
+s
+n
+1.2449 0.5250 m
+1.2249 0.5250 l
+s
+n
+0.1000 0.7375 m
+0.1200 0.7375 l
+s
+n
+1.2449 0.7375 m
+1.2249 0.7375 l
+s
+n
+0.1000 0.9500 m
+0.1200 0.9500 l
+s
+n
+1.2449 0.9500 m
+1.2249 0.9500 l
+s
+/Font4 FFSF
+0.0602 0.0878 m
+GS
+[0.0350 0.0000 0.0000 0.0350 0 0] CC
+(-2) show
+GR
+/Font4 FFSF
+0.0661 0.3001 m
+GS
+[0.0350 0.0000 0.0000 0.0350 0 0] CC
+(-1) show
+GR
+/Font4 FFSF
+0.0724 0.5130 m
+GS
+[0.0350 0.0000 0.0000 0.0350 0 0] CC
+(0) show
+GR
+/Font4 FFSF
+0.0778 0.7251 m
+GS
+[0.0350 0.0000 0.0000 0.0350 0 0] CC
+(1) show
+GR
+/Font4 FFSF
+0.0720 0.9378 m
+GS
+[0.0350 0.0000 0.0000 0.0350 0 0] CC
+(2) show
+GR
+/Font4 FFSF
+0.0412 0.3446 m
+GS
+[0.0000 0.0420 -0.0420 0.0000 0 0] CC
+(Electric field \(V/nm\)) show
+GR
+n
+0.1000 0.1000 m
+0.1000 0.9500 l
+1.2449 0.9500 l
+1.2449 0.1000 l
+0.1000 0.1000 l
+c
+s
+%%Trailer
+%%DocumentNeededResources: font Helvetica
+%%EOF
diff --git a/docs/manual/plots/field.xvg b/docs/manual/plots/field.xvg
new file mode 100644 (file)
index 0000000..0e333d3
--- /dev/null
@@ -0,0 +1,4299 @@
+# Grace project file
+#
+@version 50125
+@page size 792, 612
+@page scroll 5%
+@page inout 5%
+@link page off
+@map font 0 to "Times-Roman", "Times-Roman"
+@map font 1 to "Times-Italic", "Times-Italic"
+@map font 2 to "Times-Bold", "Times-Bold"
+@map font 3 to "Times-BoldItalic", "Times-BoldItalic"
+@map font 4 to "Helvetica", "Helvetica"
+@map font 5 to "Helvetica-Oblique", "Helvetica-Oblique"
+@map font 6 to "Helvetica-Bold", "Helvetica-Bold"
+@map font 7 to "Helvetica-BoldOblique", "Helvetica-BoldOblique"
+@map font 8 to "Courier", "Courier"
+@map font 9 to "Courier-Oblique", "Courier-Oblique"
+@map font 10 to "Courier-Bold", "Courier-Bold"
+@map font 11 to "Courier-BoldOblique", "Courier-BoldOblique"
+@map font 12 to "Symbol", "Symbol"
+@map font 13 to "ZapfDingbats", "ZapfDingbats"
+@map color 0 to (255, 255, 255), "white"
+@map color 1 to (0, 0, 0), "black"
+@map color 2 to (255, 0, 0), "red"
+@map color 3 to (0, 255, 0), "green"
+@map color 4 to (0, 0, 255), "blue"
+@map color 5 to (255, 255, 0), "yellow"
+@map color 6 to (188, 143, 143), "brown"
+@map color 7 to (220, 220, 220), "grey"
+@map color 8 to (148, 0, 211), "violet"
+@map color 9 to (0, 255, 255), "cyan"
+@map color 10 to (255, 0, 255), "magenta"
+@map color 11 to (255, 165, 0), "orange"
+@map color 12 to (114, 33, 188), "indigo"
+@map color 13 to (103, 7, 72), "maroon"
+@map color 14 to (64, 224, 208), "turquoise"
+@map color 15 to (0, 139, 0), "green4"
+@reference date 0
+@date wrap off
+@date wrap year 1950
+@default linewidth 1.0
+@default linestyle 1
+@default color 1
+@default pattern 1
+@default font 0
+@default char size 1.000000
+@default symbol size 1.000000
+@default sformat "%.8g"
+@background color 0
+@page background fill on
+@timestamp off
+@timestamp 0.03, 0.03
+@timestamp color 1
+@timestamp rot 0
+@timestamp font 0
+@timestamp char size 1.000000
+@timestamp def "Tue Jul  5 08:29:55 2016"
+@r0 off
+@link r0 to g0
+@r0 type above
+@r0 linestyle 1
+@r0 linewidth 1.0
+@r0 color 1
+@r0 line 0, 0, 0, 0
+@r1 off
+@link r1 to g0
+@r1 type above
+@r1 linestyle 1
+@r1 linewidth 1.0
+@r1 color 1
+@r1 line 0, 0, 0, 0
+@r2 off
+@link r2 to g0
+@r2 type above
+@r2 linestyle 1
+@r2 linewidth 1.0
+@r2 color 1
+@r2 line 0, 0, 0, 0
+@r3 off
+@link r3 to g0
+@r3 type above
+@r3 linestyle 1
+@r3 linewidth 1.0
+@r3 color 1
+@r3 line 0, 0, 0, 0
+@r4 off
+@link r4 to g0
+@r4 type above
+@r4 linestyle 1
+@r4 linewidth 1.0
+@r4 color 1
+@r4 line 0, 0, 0, 0
+@g0 on
+@g0 hidden false
+@g0 type XY
+@g0 stacked false
+@g0 bar hgap 0.000000
+@g0 fixedpoint off
+@g0 fixedpoint type 0
+@g0 fixedpoint xy 0.000000, 0.000000
+@g0 fixedpoint format general general
+@g0 fixedpoint prec 6, 6
+@with g0
+@    world 0, -2, 2, 2
+@    stack world 0, 0, 0, 0
+@    znorm 1
+@    view 0.100000, 0.100000, 1.244903, 0.950000
+@    title ""
+@    title font 0
+@    title size 1.500000
+@    title color 1
+@    subtitle ""
+@    subtitle font 0
+@    subtitle size 1.000000
+@    subtitle color 1
+@    xaxes scale Normal
+@    yaxes scale Normal
+@    xaxes invert off
+@    yaxes invert off
+@    xaxis  on
+@    xaxis  type zero false
+@    xaxis  offset 0.000000 , 0.000000
+@    xaxis  bar on
+@    xaxis  bar color 1
+@    xaxis  bar linestyle 1
+@    xaxis  bar linewidth 1.0
+@    xaxis  label "Time (ps)"
+@    xaxis  label layout para
+@    xaxis  label place auto
+@    xaxis  label char size 1.500000
+@    xaxis  label font 4
+@    xaxis  label color 1
+@    xaxis  label place normal
+@    xaxis  tick on
+@    xaxis  tick major 0.5
+@    xaxis  tick minor ticks 1
+@    xaxis  tick default 6
+@    xaxis  tick place rounded true
+@    xaxis  tick in
+@    xaxis  tick major size 1.000000
+@    xaxis  tick major color 1
+@    xaxis  tick major linewidth 1.0
+@    xaxis  tick major linestyle 1
+@    xaxis  tick major grid off
+@    xaxis  tick minor color 1
+@    xaxis  tick minor linewidth 1.0
+@    xaxis  tick minor linestyle 1
+@    xaxis  tick minor grid off
+@    xaxis  tick minor size 0.500000
+@    xaxis  ticklabel on
+@    xaxis  ticklabel format general
+@    xaxis  ticklabel prec 5
+@    xaxis  ticklabel formula ""
+@    xaxis  ticklabel append ""
+@    xaxis  ticklabel prepend ""
+@    xaxis  ticklabel angle 0
+@    xaxis  ticklabel skip 0
+@    xaxis  ticklabel stagger 0
+@    xaxis  ticklabel place normal
+@    xaxis  ticklabel offset auto
+@    xaxis  ticklabel offset 0.000000 , 0.010000
+@    xaxis  ticklabel start type auto
+@    xaxis  ticklabel start 0.000000
+@    xaxis  ticklabel stop type auto
+@    xaxis  ticklabel stop 0.000000
+@    xaxis  ticklabel char size 1.250000
+@    xaxis  ticklabel font 4
+@    xaxis  ticklabel color 1
+@    xaxis  tick place both
+@    xaxis  tick spec type none
+@    yaxis  on
+@    yaxis  type zero false
+@    yaxis  offset 0.000000 , 0.000000
+@    yaxis  bar on
+@    yaxis  bar color 1
+@    yaxis  bar linestyle 1
+@    yaxis  bar linewidth 1.0
+@    yaxis  label "Electric field (V/nm)"
+@    yaxis  label layout para
+@    yaxis  label place auto
+@    yaxis  label char size 1.500000
+@    yaxis  label font 4
+@    yaxis  label color 1
+@    yaxis  label place normal
+@    yaxis  tick on
+@    yaxis  tick major 1
+@    yaxis  tick minor ticks 1
+@    yaxis  tick default 6
+@    yaxis  tick place rounded true
+@    yaxis  tick in
+@    yaxis  tick major size 1.000000
+@    yaxis  tick major color 1
+@    yaxis  tick major linewidth 1.0
+@    yaxis  tick major linestyle 1
+@    yaxis  tick major grid off
+@    yaxis  tick minor color 1
+@    yaxis  tick minor linewidth 1.0
+@    yaxis  tick minor linestyle 1
+@    yaxis  tick minor grid off
+@    yaxis  tick minor size 0.500000
+@    yaxis  ticklabel on
+@    yaxis  ticklabel format general
+@    yaxis  ticklabel prec 5
+@    yaxis  ticklabel formula ""
+@    yaxis  ticklabel append ""
+@    yaxis  ticklabel prepend ""
+@    yaxis  ticklabel angle 0
+@    yaxis  ticklabel skip 0
+@    yaxis  ticklabel stagger 0
+@    yaxis  ticklabel place normal
+@    yaxis  ticklabel offset auto
+@    yaxis  ticklabel offset 0.000000 , 0.010000
+@    yaxis  ticklabel start type auto
+@    yaxis  ticklabel start 0.000000
+@    yaxis  ticklabel stop type auto
+@    yaxis  ticklabel stop 0.000000
+@    yaxis  ticklabel char size 1.250000
+@    yaxis  ticklabel font 4
+@    yaxis  ticklabel color 1
+@    yaxis  tick place both
+@    yaxis  tick spec type none
+@    altxaxis  off
+@    altyaxis  off
+@    legend on
+@    legend loctype view
+@    legend 0.85, 0.8
+@    legend box color 1
+@    legend box pattern 1
+@    legend box linewidth 1.0
+@    legend box linestyle 1
+@    legend box fill color 0
+@    legend box fill pattern 1
+@    legend font 0
+@    legend char size 1.000000
+@    legend color 1
+@    legend length 4
+@    legend vgap 1
+@    legend hgap 1
+@    legend invert false
+@    frame type 0
+@    frame linestyle 1
+@    frame linewidth 1.0
+@    frame color 1
+@    frame pattern 1
+@    frame background color 0
+@    frame background pattern 0
+@    s0 hidden false
+@    s0 type xy
+@    s0 symbol 0
+@    s0 symbol size 1.000000
+@    s0 symbol color 1
+@    s0 symbol pattern 1
+@    s0 symbol fill color 1
+@    s0 symbol fill pattern 0
+@    s0 symbol linewidth 1.0
+@    s0 symbol linestyle 1
+@    s0 symbol char 65
+@    s0 symbol char font 0
+@    s0 symbol skip 0
+@    s0 line type 1
+@    s0 line linestyle 1
+@    s0 line linewidth 1.0
+@    s0 line color 1
+@    s0 line pattern 1
+@    s0 baseline type 0
+@    s0 baseline off
+@    s0 dropline off
+@    s0 fill type 0
+@    s0 fill rule 0
+@    s0 fill color 1
+@    s0 fill pattern 1
+@    s0 avalue off
+@    s0 avalue type 2
+@    s0 avalue char size 1.000000
+@    s0 avalue font 0
+@    s0 avalue color 1
+@    s0 avalue rot 0
+@    s0 avalue format general
+@    s0 avalue prec 3
+@    s0 avalue prepend ""
+@    s0 avalue append ""
+@    s0 avalue offset 0.000000 , 0.000000
+@    s0 errorbar on
+@    s0 errorbar place both
+@    s0 errorbar color 1
+@    s0 errorbar pattern 1
+@    s0 errorbar size 1.000000
+@    s0 errorbar linewidth 1.0
+@    s0 errorbar linestyle 1
+@    s0 errorbar riser linewidth 1.0
+@    s0 errorbar riser linestyle 1
+@    s0 errorbar riser clip off
+@    s0 errorbar riser clip length 0.100000
+@    s0 comment "field.xvg"
+@    s0 legend  ""
+@target G0.S0
+@type xy
+0 5.21174e-06
+0.0005 4.8582e-06
+0.001 4.46725e-06
+0.0015 4.04017e-06
+0.002 3.57871e-06
+0.0025 3.08465e-06
+0.003 2.56005e-06
+0.0035 2.0072e-06
+0.004 1.42855e-06
+0.0045 8.27051e-07
+0.005 2.0556e-07
+0.0055 -4.3279e-07
+0.006 -1.08468e-06
+0.0065 -1.74674e-06
+0.007 -2.4151e-06
+0.0075 -3.08612e-06
+0.008 -3.75593e-06
+0.0085 -4.42057e-06
+0.009 -5.07613e-06
+0.0095 -5.7183e-06
+0.01 -6.34309e-06
+0.0105 -6.94642e-06
+0.011 -7.52419e-06
+0.0115 -8.07249e-06
+0.012 -8.58716e-06
+0.0125 -9.06443e-06
+0.013 -9.5006e-06
+0.0135 -9.89205e-06
+0.014 -1.02354e-05
+0.0145 -1.05275e-05
+0.015 -1.07651e-05
+0.0155 -1.09458e-05
+0.016 -1.10668e-05
+0.0165 -1.11262e-05
+0.017 -1.11219e-05
+0.0175 -1.10524e-05
+0.018 -1.09166e-05
+0.0185 -1.07135e-05
+0.019 -1.04426e-05
+0.0195 -1.01039e-05
+0.02 -9.69779e-06
+0.0205 -9.22485e-06
+0.021 -8.68609e-06
+0.0215 -8.0833e-06
+0.022 -7.41831e-06
+0.0225 -6.69347e-06
+0.023 -5.91155e-06
+0.0235 -5.07554e-06
+0.024 -4.18956e-06
+0.0245 -3.25681e-06
+0.025 -2.28218e-06
+0.0255 -1.27017e-06
+0.026 -2.25546e-07
+0.0265 8.45705e-07
+0.027 1.93884e-06
+0.0275 3.04734e-06
+0.028 4.1653e-06
+0.0285 5.28662e-06
+0.029 6.40417e-06
+0.0295 7.51217e-06
+0.03 8.60324e-06
+0.0305 9.67081e-06
+0.031 1.07082e-05
+0.0315 1.17081e-05
+0.032 1.26644e-05
+0.0325 1.357e-05
+0.033 1.44184e-05
+0.0335 1.52034e-05
+0.034 1.59185e-05
+0.0345 1.65582e-05
+0.035 1.71168e-05
+0.0355 1.75889e-05
+0.036 1.79698e-05
+0.0365 1.82549e-05
+0.037 1.84404e-05
+0.0375 1.85226e-05
+0.038 1.84986e-05
+0.0385 1.83658e-05
+0.039 1.81227e-05
+0.0395 1.77676e-05
+0.04 1.73001e-05
+0.0405 1.67203e-05
+0.041 1.60287e-05
+0.0415 1.52266e-05
+0.042 1.4316e-05
+0.0425 1.32999e-05
+0.043 1.21814e-05
+0.0435 1.09648e-05
+0.044 9.65433e-06
+0.0445 8.2561e-06
+0.045 6.77585e-06
+0.0455 5.22026e-06
+0.046 3.59662e-06
+0.0465 1.91244e-06
+0.047 1.76813e-07
+0.0475 -1.60169e-06
+0.048 -3.4137e-06
+0.0485 -5.24943e-06
+0.049 -7.09906e-06
+0.0495 -8.95136e-06
+0.05 -1.0796e-05
+0.0505 -1.26218e-05
+0.051 -1.44179e-05
+0.0515 -1.61733e-05
+0.052 -1.7876e-05
+0.0525 -1.95152e-05
+0.053 -2.10797e-05
+0.0535 -2.25588e-05
+0.054 -2.39418e-05
+0.0545 -2.52179e-05
+0.055 -2.63773e-05
+0.0555 -2.74107e-05
+0.056 -2.83084e-05
+0.0565 -2.90627e-05
+0.057 -2.96652e-05
+0.0575 -3.0109e-05
+0.058 -3.03877e-05
+0.0585 -3.04957e-05
+0.059 -3.04283e-05
+0.0595 -3.01817e-05
+0.06 -2.97532e-05
+0.0605 -2.9141e-05
+0.061 -2.83441e-05
+0.0615 -2.73627e-05
+0.062 -2.61986e-05
+0.0625 -2.48541e-05
+0.063 -2.33327e-05
+0.0635 -2.16391e-05
+0.064 -1.97788e-05
+0.0645 -1.77594e-05
+0.065 -1.55887e-05
+0.0655 -1.32758e-05
+0.066 -1.08307e-05
+0.0665 -8.26413e-06
+0.067 -5.58933e-06
+0.0675 -2.8188e-06
+0.068 3.3503e-08
+0.0685 2.95285e-06
+0.069 5.92437e-06
+0.0695 8.93009e-06
+0.07 1.19557e-05
+0.0705 1.49822e-05
+0.071 1.79924e-05
+0.0715 2.09691e-05
+0.072 2.38928e-05
+0.0725 2.67458e-05
+0.073 2.95098e-05
+0.0735 3.21666e-05
+0.074 3.46986e-05
+0.0745 3.70872e-05
+0.075 3.93155e-05
+0.0755 4.13667e-05
+0.076 4.32248e-05
+0.0765 4.48746e-05
+0.077 4.63011e-05
+0.0775 4.74911e-05
+0.078 4.8432e-05
+0.0785 4.91127e-05
+0.079 4.95229e-05
+0.0795 4.96542e-05
+0.08 4.94991e-05
+0.0805 4.90519e-05
+0.081 4.83086e-05
+0.0815 4.72662e-05
+0.082 4.59245e-05
+0.0825 4.4284e-05
+0.083 4.23475e-05
+0.0835 4.01187e-05
+0.084 3.76052e-05
+0.0845 3.48143e-05
+0.085 3.1756e-05
+0.0855 2.8442e-05
+0.086 2.48848e-05
+0.0865 2.11021e-05
+0.087 1.71074e-05
+0.0875 1.29217e-05
+0.088 8.5642e-06
+0.0885 4.05536e-06
+0.089 -5.79145e-07
+0.0895 -5.31895e-06
+0.09 -1.01359e-05
+0.0905 -1.50047e-05
+0.091 -1.98991e-05
+0.0915 -2.47881e-05
+0.092 -2.96471e-05
+0.0925 -3.44439e-05
+0.093 -3.91504e-05
+0.0935 -4.37376e-05
+0.094 -4.81737e-05
+0.0945 -5.24325e-05
+0.095 -5.64828e-05
+0.0955 -6.02969e-05
+0.096 -6.38478e-05
+0.0965 -6.7107e-05
+0.097 -7.00511e-05
+0.0975 -7.26541e-05
+0.098 -7.48937e-05
+0.0985 -7.67485e-05
+0.099 -7.81986e-05
+0.0995 -7.92268e-05
+0.1 -7.98172e-05
+0.1005 -7.99564e-05
+0.101 -7.96334e-05
+0.1015 -7.884e-05
+0.102 -7.75691e-05
+0.1025 -7.58184e-05
+0.103 -7.35867e-05
+0.1035 -7.08762e-05
+0.104 -6.76919e-05
+0.1045 -6.40408e-05
+0.105 -5.99352e-05
+0.1055 -5.53879e-05
+0.106 -5.04157e-05
+0.1065 -4.50365e-05
+0.107 -3.92749e-05
+0.1075 -3.31549e-05
+0.108 -2.67039e-05
+0.1085 -1.9952e-05
+0.109 -1.2932e-05
+0.1095 -5.67709e-06
+0.11 1.77265e-06
+0.1105 9.37968e-06
+0.111 1.71032e-05
+0.1115 2.49024e-05
+0.112 3.27304e-05
+0.1125 4.05437e-05
+0.113 4.82966e-05
+0.1135 5.59424e-05
+0.114 6.34357e-05
+0.1145 7.07264e-05
+0.115 7.77691e-05
+0.1155 8.45172e-05
+0.116 9.09248e-05
+0.1165 9.69478e-05
+0.117 0.000102541
+0.1175 0.000107662
+0.118 0.000112273
+0.1185 0.000116332
+0.119 0.000119806
+0.1195 0.000122661
+0.12 0.000124867
+0.1205 0.000126395
+0.121 0.000127223
+0.1215 0.00012733
+0.122 0.000126699
+0.1225 0.000125318
+0.123 0.000123178
+0.1235 0.000120274
+0.124 0.000116606
+0.1245 0.00011218
+0.125 0.000107004
+0.1255 0.000101092
+0.126 9.44624e-05
+0.1265 8.71353e-05
+0.127 7.91416e-05
+0.1275 7.05119e-05
+0.128 6.12822e-05
+0.1285 5.14929e-05
+0.129 4.11867e-05
+0.1295 3.04165e-05
+0.13 1.92326e-05
+0.1305 7.69112e-06
+0.131 -4.14868e-06
+0.1315 -1.62269e-05
+0.132 -2.8471e-05
+0.1325 -4.08232e-05
+0.133 -5.32067e-05
+0.1335 -6.55524e-05
+0.134 -7.77902e-05
+0.1345 -8.98416e-05
+0.135 -0.000101635
+0.1355 -0.000113095
+0.136 -0.000124152
+0.1365 -0.000134726
+0.137 -0.000144748
+0.1375 -0.00015415
+0.138 -0.000162861
+0.1385 -0.000170816
+0.139 -0.000177954
+0.1395 -0.000184212
+0.14 -0.000189537
+0.1405 -0.000193877
+0.141 -0.000197186
+0.1415 -0.000199421
+0.142 -0.000200548
+0.1425 -0.000200535
+0.143 -0.000199357
+0.1435 -0.000196997
+0.144 -0.000193441
+0.1445 -0.000188686
+0.145 -0.000182733
+0.1455 -0.000175591
+0.146 -0.000167273
+0.1465 -0.000157807
+0.147 -0.000147221
+0.1475 -0.000135553
+0.148 -0.000122847
+0.1485 -0.000109154
+0.149 -9.45312e-05
+0.1495 -7.90457e-05
+0.15 -6.27703e-05
+0.1505 -4.57812e-05
+0.151 -2.816e-05
+0.1515 -9.9992e-06
+0.152 8.61086e-06
+0.1525 2.75697e-05
+0.153 4.67707e-05
+0.1535 6.61152e-05
+0.154 8.54878e-05
+0.1545 0.000104781
+0.155 0.000123874
+0.1555 0.00014266
+0.156 0.000161019
+0.1565 0.000178834
+0.157 0.000195993
+0.1575 0.00021238
+0.158 0.000227882
+0.1585 0.000242394
+0.159 0.000255808
+0.1595 0.000268024
+0.16 0.000278943
+0.1605 0.000288479
+0.161 0.000296543
+0.1615 0.000303058
+0.162 0.000307954
+0.1625 0.000311168
+0.163 0.000312645
+0.1635 0.00031234
+0.164 0.000310218
+0.1645 0.000306253
+0.165 0.000300429
+0.1655 0.00029274
+0.166 0.000283191
+0.1665 0.0002718
+0.167 0.000258592
+0.1675 0.000243609
+0.168 0.000226898
+0.1685 0.000208519
+0.169 0.000188545
+0.1695 0.000167064
+0.17 0.000144158
+0.1705 0.00011994
+0.171 9.45162e-05
+0.1715 6.8015e-05
+0.172 4.0565e-05
+0.1725 1.23028e-05
+0.173 -1.66184e-05
+0.1735 -4.60506e-05
+0.174 -7.58303e-05
+0.1745 -0.000105786
+0.175 -0.000135759
+0.1755 -0.00016557
+0.176 -0.00019504
+0.1765 -0.000223991
+0.177 -0.000252251
+0.1775 -0.000279638
+0.178 -0.00030597
+0.1785 -0.000331079
+0.179 -0.000354791
+0.1795 -0.000376935
+0.18 -0.000397359
+0.1805 -0.000415904
+0.181 -0.000432421
+0.1815 -0.000446777
+0.182 -0.00045884
+0.1825 -0.000468496
+0.183 -0.000475638
+0.1835 -0.000480172
+0.184 -0.000482019
+0.1845 -0.000481113
+0.185 -0.000477401
+0.1855 -0.000470848
+0.186 -0.000461434
+0.1865 -0.000449155
+0.187 -0.000434021
+0.1875 -0.000416065
+0.188 -0.000395332
+0.1885 -0.000371882
+0.189 -0.000345801
+0.1895 -0.000317184
+0.19 -0.000286141
+0.1905 -0.000252807
+0.191 -0.000217334
+0.1915 -0.000179872
+0.192 -0.000140603
+0.1925 -9.97231e-05
+0.193 -5.7428e-05
+0.1935 -1.39473e-05
+0.194 3.05086e-05
+0.1945 7.56883e-05
+0.195 0.000121353
+0.1955 0.000167245
+0.196 0.000213091
+0.1965 0.000258644
+0.197 0.000303625
+0.1975 0.000347756
+0.198 0.000390773
+0.1985 0.0004324
+0.199 0.000472359
+0.1995 0.000510397
+0.2 0.000546255
+0.2005 0.000579676
+0.201 0.000610412
+0.2015 0.000638241
+0.202 0.000662939
+0.2025 0.000684297
+0.203 0.000702128
+0.2035 0.000716255
+0.204 0.000726522
+0.2045 0.000732793
+0.205 0.000734951
+0.2055 0.0007329
+0.206 0.000726571
+0.2065 0.000715911
+0.207 0.000700895
+0.2075 0.000681526
+0.208 0.000657829
+0.2085 0.00062985
+0.209 0.000597673
+0.2095 0.000561393
+0.21 0.000521145
+0.2105 0.000477082
+0.211 0.000429382
+0.2115 0.000378243
+0.212 0.000323899
+0.2125 0.000266607
+0.213 0.000206634
+0.2135 0.000144268
+0.214 7.98362e-05
+0.2145 1.36575e-05
+0.215 -5.39127e-05
+0.2155 -0.000122496
+0.216 -0.000191745
+0.2165 -0.000261247
+0.217 -0.000330622
+0.2175 -0.000399443
+0.218 -0.000467329
+0.2185 -0.000533853
+0.219 -0.000598597
+0.2195 -0.000661164
+0.22 -0.000721143
+0.2205 -0.000778123
+0.221 -0.000831738
+0.2215 -0.000881594
+0.222 -0.000927342
+0.2225 -0.00096862
+0.223 -0.00100512
+0.2235 -0.00103652
+0.224 -0.00106255
+0.2245 -0.00108295
+0.225 -0.00109749
+0.2255 -0.00110598
+0.226 -0.00110824
+0.2265 -0.00110414
+0.227 -0.00109358
+0.2275 -0.0010765
+0.228 -0.00105286
+0.2285 -0.00102268
+0.229 -0.000986009
+0.2295 -0.000942923
+0.23 -0.000893556
+0.2305 -0.000838068
+0.231 -0.000776655
+0.2315 -0.000709563
+0.232 -0.000637087
+0.2325 -0.00055951
+0.233 -0.000477207
+0.2335 -0.000390545
+0.234 -0.000299961
+0.2345 -0.000205893
+0.235 -0.000108808
+0.2355 -9.23019e-06
+0.236 9.23325e-05
+0.2365 0.000195321
+0.237 0.000299144
+0.2375 0.000403262
+0.238 0.000507054
+0.2385 0.000609903
+0.239 0.000711199
+0.2395 0.000810355
+0.24 0.000906734
+0.2405 0.000999717
+0.241 0.00108872
+0.2415 0.00117314
+0.242 0.00125239
+0.2425 0.00132595
+0.243 0.00139325
+0.2435 0.00145379
+0.244 0.0015071
+0.2445 0.00155272
+0.245 0.00159025
+0.2455 0.00161932
+0.246 0.0016396
+0.2465 0.00165079
+0.247 0.00165268
+0.2475 0.00164506
+0.248 0.0016278
+0.2485 0.00160082
+0.249 0.0015641
+0.2495 0.00151765
+0.25 0.00146156
+0.2505 0.00139598
+0.251 0.0013211
+0.2515 0.00123719
+0.252 0.00114455
+0.2525 0.00104356
+0.253 0.000934631
+0.2535 0.000818285
+0.254 0.000695002
+0.2545 0.000565389
+0.255 0.000430088
+0.2555 0.000289763
+0.256 0.000145101
+0.2565 -3.06876e-06
+0.257 -0.000154016
+0.2575 -0.000306921
+0.258 -0.000460919
+0.2585 -0.000615112
+0.259 -0.000768673
+0.2595 -0.000920672
+0.26 -0.00107018
+0.2605 -0.00121633
+0.261 -0.00135819
+0.2615 -0.00149484
+0.262 -0.00162542
+0.2625 -0.00174908
+0.263 -0.00186495
+0.2635 -0.0019722
+0.264 -0.00207009
+0.2645 -0.00215786
+0.265 -0.00223481
+0.2655 -0.00230031
+0.266 -0.00235376
+0.2665 -0.00239462
+0.267 -0.00242243
+0.2675 -0.0024368
+0.268 -0.00243738
+0.2685 -0.00242393
+0.269 -0.00239625
+0.2695 -0.00235424
+0.27 -0.0022979
+0.2705 -0.00222727
+0.271 -0.0021425
+0.2715 -0.00204382
+0.272 -0.00193154
+0.2725 -0.00180607
+0.273 -0.00166791
+0.2735 -0.00151759
+0.274 -0.00135576
+0.2745 -0.00118314
+0.275 -0.00100057
+0.2755 -0.000808891
+0.276 -0.000609027
+0.2765 -0.000402025
+0.277 -0.000188906
+0.2775 2.91893e-05
+0.278 0.000251046
+0.2785 0.00047552
+0.279 0.000701385
+0.2795 0.000927272
+0.28 0.0011519
+0.2805 0.00137402
+0.281 0.00159225
+0.2815 0.00180524
+0.282 0.00201172
+0.2825 0.00221035
+0.283 0.0023998
+0.2835 0.00257887
+0.284 0.00274636
+0.2845 0.00290102
+0.285 0.00304176
+0.2855 0.00316753
+0.286 0.00327733
+0.2865 0.00337022
+0.287 0.00344538
+0.2875 0.00350205
+0.288 0.00353956
+0.2885 0.00355737
+0.289 0.00355501
+0.2895 0.00353213
+0.29 0.00348852
+0.2905 0.00342402
+0.291 0.00333865
+0.2915 0.00323254
+0.292 0.00310591
+0.2925 0.00295915
+0.293 0.00279274
+0.2935 0.00260726
+0.294 0.00240346
+0.2945 0.00218224
+0.295 0.0019445
+0.2955 0.00169129
+0.296 0.0014239
+0.2965 0.00114356
+0.297 0.000851664
+0.2975 0.000549661
+0.298 0.000239175
+0.2985 -7.82175e-05
+0.299 -0.000400775
+0.2995 -0.000726663
+0.3 -0.00105419
+0.3005 -0.00138144
+0.301 -0.00170647
+0.3015 -0.00202738
+0.302 -0.00234234
+0.3025 -0.00264937
+0.303 -0.00294652
+0.3035 -0.00323196
+0.304 -0.00350382
+0.3045 -0.00376024
+0.305 -0.00399958
+0.3055 -0.00422009
+0.306 -0.00442015
+0.3065 -0.00459828
+0.307 -0.00475312
+0.3075 -0.00488328
+0.308 -0.00498762
+0.3085 -0.0050651
+0.309 -0.00511479
+0.3095 -0.00513592
+0.31 -0.00512787
+0.3105 -0.00509018
+0.311 -0.00502256
+0.3115 -0.00492488
+0.312 -0.00479717
+0.3125 -0.00463965
+0.313 -0.00445273
+0.3135 -0.00423693
+0.314 -0.00399306
+0.3145 -0.003722
+0.315 -0.00342483
+0.3155 -0.00310282
+0.316 -0.00275748
+0.3165 -0.00239025
+0.317 -0.00200295
+0.3175 -0.0015975
+0.318 -0.00117589
+0.3185 -0.000740179
+0.319 -0.000292861
+0.3195 0.000163868
+0.32 0.000627539
+0.3205 0.00109555
+0.321 0.00156519
+0.3215 0.00203396
+0.322 0.00249906
+0.3225 0.0029577
+0.323 0.00340721
+0.3235 0.0038448
+0.324 0.00426768
+0.3245 0.00467327
+0.325 0.00505895
+0.3255 0.0054221
+0.326 0.00576021
+0.3265 0.00607101
+0.327 0.0063522
+0.3275 0.00660161
+0.328 0.00681734
+0.3285 0.00699752
+0.329 0.00714054
+0.3295 0.00724495
+0.33 0.00730949
+0.3305 0.00733311
+0.331 0.007315
+0.3315 0.00725454
+0.332 0.00715136
+0.3325 0.00700537
+0.333 0.00681668
+0.3335 0.00658563
+0.334 0.00631287
+0.3345 0.00599924
+0.335 0.00564587
+0.3355 0.00525422
+0.336 0.00482578
+0.3365 0.00436241
+0.337 0.00386622
+0.3375 0.00333958
+0.338 0.00278496
+0.3385 0.00220503
+0.339 0.00160282
+0.3395 0.000981312
+0.34 0.000343815
+0.3405 -0.00030613
+0.341 -0.000965188
+0.3415 -0.00162979
+0.342 -0.00229592
+0.3425 -0.00295985
+0.343 -0.00361791
+0.3435 -0.0042661
+0.344 -0.00490045
+0.3445 -0.0055172
+0.345 -0.00611246
+0.3455 -0.00668234
+0.346 -0.0072233
+0.3465 -0.00773181
+0.347 -0.00820419
+0.3475 -0.0086372
+0.348 -0.00902783
+0.3485 -0.00937304
+0.349 -0.00967006
+0.3495 -0.00991647
+0.35 -0.01011
+0.3505 -0.0102486
+0.351 -0.0103306
+0.3515 -0.0103547
+0.352 -0.0103198
+0.3525 -0.010225
+0.353 -0.01007
+0.3535 -0.00985468
+0.354 -0.00957927
+0.3545 -0.00924437
+0.355 -0.008851
+0.3555 -0.00840043
+0.356 -0.00789427
+0.3565 -0.00733459
+0.357 -0.00672387
+0.3575 -0.00606459
+0.358 -0.00535969
+0.3585 -0.00461278
+0.359 -0.00382731
+0.3595 -0.00300721
+0.36 -0.00215651
+0.3605 -0.00127982
+0.361 -0.000381554
+0.3615 0.000533364
+0.362 0.00145975
+0.3625 0.00239285
+0.363 0.00332721
+0.3635 0.00425738
+0.364 0.00517796
+0.3645 0.00608377
+0.365 0.00696918
+0.3655 0.00782868
+0.366 0.00865711
+0.3665 0.00944909
+0.367 0.0101994
+0.3675 0.0109033
+0.368 0.0115558
+0.3685 0.0121524
+0.369 0.0126887
+0.3695 0.013161
+0.37 0.0135651
+0.3705 0.0138979
+0.371 0.0141563
+0.3715 0.0143375
+0.372 0.0144394
+0.3725 0.0144601
+0.373 0.0143982
+0.3735 0.0142527
+0.374 0.0140233
+0.3745 0.0137097
+0.375 0.0133127
+0.3755 0.012833
+0.376 0.0122722
+0.3765 0.0116322
+0.377 0.0109155
+0.3775 0.0101249
+0.378 0.00926381
+0.3785 0.00833631
+0.379 0.00734629
+0.3795 0.00629867
+0.38 0.00519866
+0.3805 0.00405167
+0.381 0.00286331
+0.3815 0.00164037
+0.382 0.000388846
+0.3825 -0.000884521
+0.383 -0.00217263
+0.3835 -0.00346804
+0.384 -0.00476396
+0.3845 -0.00605269
+0.385 -0.00732657
+0.3855 -0.00857832
+0.386 -0.00980029
+0.3865 -0.0109847
+0.387 -0.0121247
+0.3875 -0.0132128
+0.388 -0.0142421
+0.3885 -0.0152053
+0.389 -0.0160965
+0.3895 -0.0169092
+0.39 -0.0176373
+0.3905 -0.0182757
+0.391 -0.018819
+0.3915 -0.0192629
+0.392 -0.0196032
+0.3925 -0.0198365
+0.393 -0.0199596
+0.3935 -0.0199703
+0.394 -0.0198667
+0.3945 -0.0196477
+0.395 -0.0193128
+0.3955 -0.0188622
+0.396 -0.0182966
+0.3965 -0.0176176
+0.397 -0.0168273
+0.3975 -0.0159286
+0.398 -0.0149253
+0.3985 -0.0138211
+0.399 -0.0126209
+0.3995 -0.0113302
+0.4 -0.0099553
+0.4005 -0.00850257
+0.401 -0.00697904
+0.4015 -0.00539271
+0.402 -0.00375142
+0.4025 -0.00206392
+0.403 -0.000339552
+0.4035 0.00141286
+0.404 0.00318388
+0.4045 0.00496288
+0.405 0.00673997
+0.4055 0.00850546
+0.406 0.0102487
+0.4065 0.0119591
+0.407 0.0136268
+0.4075 0.0152414
+0.408 0.0167925
+0.4085 0.0182707
+0.409 0.0196666
+0.4095 0.0209704
+0.41 0.0221735
+0.4105 0.0232677
+0.411 0.0242449
+0.4115 0.0250978
+0.412 0.0258196
+0.4125 0.0264044
+0.413 0.0268466
+0.4135 0.0271417
+0.414 0.0272858
+0.4145 0.0272758
+0.415 0.0271096
+0.4155 0.0267857
+0.416 0.0263037
+0.4165 0.0256642
+0.417 0.0248683
+0.4175 0.0239184
+0.418 0.0228178
+0.4185 0.0215703
+0.419 0.0201811
+0.4195 0.0186564
+0.42 0.0170024
+0.4205 0.0152267
+0.421 0.0133383
+0.4215 0.011346
+0.422 0.00925979
+0.4225 0.00709001
+0.423 0.00484833
+0.4235 0.00254611
+0.424 0.000195897
+0.4245 -0.00218904
+0.425 -0.0045965
+0.4255 -0.00701253
+0.426 -0.00942313
+0.4265 -0.0118144
+0.427 -0.0141732
+0.4275 -0.0164848
+0.428 -0.0187353
+0.4285 -0.0209112
+0.429 -0.0229988
+0.4295 -0.0249845
+0.43 -0.0268561
+0.4305 -0.028601
+0.431 -0.0302072
+0.4315 -0.0316634
+0.432 -0.0329599
+0.4325 -0.034086
+0.433 -0.0350334
+0.4335 -0.0357939
+0.434 -0.0363606
+0.4345 -0.0367274
+0.435 -0.0368894
+0.4355 -0.0368427
+0.436 -0.0365846
+0.4365 -0.0361138
+0.437 -0.0354296
+0.4375 -0.0345333
+0.438 -0.0334268
+0.4385 -0.0321134
+0.439 -0.0305979
+0.4395 -0.0288861
+0.44 -0.0269848
+0.4405 -0.0249024
+0.441 -0.0226488
+0.4415 -0.0202334
+0.442 -0.0176684
+0.4425 -0.0149667
+0.443 -0.0121414
+0.4435 -0.00920658
+0.444 -0.00617889
+0.4445 -0.00307319
+0.445 9.38279e-05
+0.4455 0.00330456
+0.446 0.00654057
+0.4465 0.00978498
+0.447 0.0130187
+0.4475 0.0162226
+0.448 0.0193787
+0.4485 0.0224679
+0.449 0.025471
+0.4495 0.0283705
+0.45 0.0311483
+0.4505 0.0337865
+0.451 0.0362676
+0.4515 0.0385763
+0.452 0.0406963
+0.4525 0.0426129
+0.453 0.0443125
+0.4535 0.0457821
+0.454 0.0470104
+0.4545 0.0479869
+0.455 0.0487028
+0.4555 0.0491501
+0.456 0.0493228
+0.4565 0.049216
+0.457 0.0488265
+0.4575 0.0481527
+0.458 0.0471947
+0.4585 0.0459539
+0.459 0.0444338
+0.4595 0.0426389
+0.46 0.040576
+0.4605 0.0382538
+0.461 0.0356813
+0.4615 0.0328698
+0.462 0.0298324
+0.4625 0.0265838
+0.463 0.0231394
+0.4635 0.0195159
+0.464 0.0157324
+0.4645 0.0118076
+0.465 0.00776245
+0.4655 0.00361934
+0.466 -0.000600586
+0.4665 -0.00487467
+0.467 -0.00917742
+0.4675 -0.0134851
+0.468 -0.0177743
+0.4685 -0.0220194
+0.469 -0.0261952
+0.4695 -0.0302776
+0.47 -0.0342415
+0.4705 -0.0380621
+0.471 -0.0417166
+0.4715 -0.0451823
+0.472 -0.0484354
+0.4725 -0.0514549
+0.473 -0.0542213
+0.4735 -0.0567147
+0.474 -0.0589172
+0.4745 -0.0608126
+0.475 -0.0623858
+0.4755 -0.0636236
+0.476 -0.0645146
+0.4765 -0.065049
+0.477 -0.065219
+0.4775 -0.0650191
+0.478 -0.0644453
+0.4785 -0.0634961
+0.479 -0.0621721
+0.4795 -0.0604757
+0.48 -0.058412
+0.4805 -0.055988
+0.481 -0.0532125
+0.4815 -0.0500969
+0.482 -0.0466555
+0.4825 -0.0429026
+0.483 -0.0388552
+0.4835 -0.0345342
+0.484 -0.0299599
+0.4845 -0.0251554
+0.485 -0.0201444
+0.4855 -0.014954
+0.486 -0.00961063
+0.4865 -0.00414326
+0.487 0.00141726
+0.4875 0.00704261
+0.488 0.0127003
+0.4885 0.0183578
+0.489 0.0239829
+0.4895 0.0295446
+0.49 0.0350091
+0.4905 0.0403434
+0.491 0.0455165
+0.4915 0.0504961
+0.492 0.0552504
+0.4925 0.0597511
+0.493 0.0639685
+0.4935 0.0678742
+0.494 0.0714423
+0.4945 0.0746493
+0.495 0.0774705
+0.4955 0.0798857
+0.496 0.081876
+0.4965 0.0834246
+0.497 0.0845167
+0.4975 0.0851407
+0.498 0.0852869
+0.4985 0.0849485
+0.499 0.0841214
+0.4995 0.082804
+0.5 0.0809979
+0.5005 0.0787068
+0.501 0.0759384
+0.5015 0.0727022
+0.502 0.0690109
+0.5025 0.0648793
+0.503 0.060326
+0.5035 0.0553728
+0.504 0.0500409
+0.5045 0.0443576
+0.505 0.03835
+0.5055 0.0320489
+0.506 0.0254881
+0.5065 0.018699
+0.507 0.011719
+0.5075 0.00458631
+0.508 -0.00266161
+0.5085 -0.00998256
+0.509 -0.0173386
+0.5095 -0.0246866
+0.51 -0.0319838
+0.5105 -0.0391894
+0.511 -0.0462588
+0.5115 -0.0531529
+0.512 -0.0598287
+0.5125 -0.0662447
+0.513 -0.0723624
+0.5135 -0.0781414
+0.514 -0.0835468
+0.5145 -0.088542
+0.515 -0.0930931
+0.5155 -0.0971695
+0.516 -0.100741
+0.5165 -0.103783
+0.517 -0.106269
+0.5175 -0.108181
+0.518 -0.109499
+0.5185 -0.110208
+0.519 -0.110299
+0.5195 -0.109762
+0.52 -0.108593
+0.5205 -0.106791
+0.521 -0.104358
+0.5215 -0.101302
+0.522 -0.0976316
+0.5225 -0.093361
+0.523 -0.0885072
+0.5235 -0.0830903
+0.524 -0.0771355
+0.5245 -0.0706694
+0.525 -0.0637239
+0.5255 -0.0563325
+0.526 -0.0485311
+0.5265 -0.040361
+0.527 -0.0318629
+0.5275 -0.0230839
+0.528 -0.0140672
+0.5285 -0.00486342
+0.529 0.00447629
+0.5295 0.0139021
+0.53 0.0233583
+0.5305 0.0327951
+0.531 0.0421565
+0.5315 0.0513873
+0.532 0.060435
+0.5325 0.0692449
+0.533 0.0777623
+0.5335 0.0859384
+0.534 0.0937202
+0.5345 0.10106
+0.535 0.10791
+0.5355 0.114225
+0.536 0.119964
+0.5365 0.125086
+0.537 0.129556
+0.5375 0.133339
+0.538 0.136408
+0.5385 0.138735
+0.539 0.140299
+0.5395 0.141083
+0.54 0.141072
+0.5405 0.140258
+0.541 0.138635
+0.5415 0.136205
+0.542 0.132971
+0.5425 0.128943
+0.543 0.124134
+0.5435 0.118563
+0.544 0.112252
+0.5445 0.105232
+0.545 0.0975308
+0.5455 0.0891869
+0.546 0.080239
+0.5465 0.0707321
+0.547 0.0607162
+0.5475 0.0502385
+0.548 0.0393566
+0.5485 0.028126
+0.549 0.0166077
+0.5495 0.00486666
+0.55 -0.00703746
+0.5505 -0.019035
+0.551 -0.031061
+0.5515 -0.0430459
+0.552 -0.0549185
+0.5525 -0.0666147
+0.553 -0.0780621
+0.5535 -0.0891951
+0.554 -0.0999452
+0.5545 -0.110245
+0.555 -0.120035
+0.5555 -0.12925
+0.556 -0.137834
+0.5565 -0.145729
+0.557 -0.152881
+0.5575 -0.159244
+0.558 -0.164772
+0.5585 -0.169423
+0.559 -0.173161
+0.5595 -0.175956
+0.56 -0.177781
+0.5605 -0.178614
+0.561 -0.17844
+0.5615 -0.177249
+0.562 -0.175036
+0.5625 -0.171803
+0.563 -0.167556
+0.5635 -0.162311
+0.564 -0.156084
+0.5645 -0.148901
+0.565 -0.140792
+0.5655 -0.131792
+0.566 -0.121947
+0.5665 -0.111299
+0.567 -0.0999022
+0.5675 -0.0878121
+0.568 -0.075091
+0.5685 -0.0618074
+0.569 -0.0480254
+0.5695 -0.0338208
+0.57 -0.0192717
+0.5705 -0.00445414
+0.571 0.0105456
+0.5715 0.0256502
+0.572 0.0407716
+0.5725 0.0558222
+0.573 0.0707186
+0.5735 0.0853704
+0.574 0.0996952
+0.5745 0.113607
+0.575 0.12702
+0.5755 0.139855
+0.576 0.152031
+0.5765 0.163472
+0.577 0.174107
+0.5775 0.183863
+0.578 0.192678
+0.5785 0.20049
+0.579 0.207245
+0.5795 0.212894
+0.58 0.217391
+0.5805 0.2207
+0.581 0.222789
+0.5815 0.223633
+0.582 0.223215
+0.5825 0.221523
+0.583 0.218554
+0.5835 0.214311
+0.584 0.208806
+0.5845 0.202055
+0.585 0.194086
+0.5855 0.18493
+0.586 0.174627
+0.5865 0.163225
+0.587 0.150776
+0.5875 0.137342
+0.588 0.122986
+0.5885 0.107783
+0.589 0.0918109
+0.5895 0.0751504
+0.59 0.0578935
+0.5905 0.0401271
+0.591 0.0219507
+0.5915 0.00346363
+0.592 -0.0152348
+0.5925 -0.0340354
+0.593 -0.052838
+0.5935 -0.0715316
+0.594 -0.0900087
+0.5945 -0.108164
+0.595 -0.12589
+0.5955 -0.143078
+0.596 -0.159631
+0.5965 -0.175443
+0.597 -0.190419
+0.5975 -0.204465
+0.598 -0.21749
+0.5985 -0.229412
+0.599 -0.24015
+0.5995 -0.249631
+0.6 -0.257791
+0.6005 -0.264566
+0.601 -0.269907
+0.6015 -0.273767
+0.602 -0.276112
+0.6025 -0.27691
+0.603 -0.276144
+0.6035 -0.2738
+0.604 -0.269879
+0.6045 -0.264384
+0.605 -0.257333
+0.6055 -0.248751
+0.606 -0.23867
+0.6065 -0.227132
+0.607 -0.214193
+0.6075 -0.199906
+0.608 -0.184346
+0.6085 -0.167583
+0.609 -0.149704
+0.6095 -0.1308
+0.61 -0.110965
+0.6105 -0.0903091
+0.611 -0.0689348
+0.6115 -0.0469612
+0.612 -0.0245075
+0.6125 -0.0016946
+0.613 0.0213488
+0.6135 0.0444974
+0.614 0.0676168
+0.6145 0.0905752
+0.615 0.113243
+0.6155 0.135485
+0.616 0.157174
+0.6165 0.178181
+0.617 0.198376
+0.6175 0.21764
+0.618 0.235853
+0.6185 0.252901
+0.619 0.268678
+0.6195 0.283078
+0.62 0.29601
+0.6205 0.307385
+0.621 0.317121
+0.6215 0.325151
+0.622 0.33141
+0.6225 0.335848
+0.623 0.338421
+0.6235 0.339096
+0.624 0.337853
+0.6245 0.33468
+0.625 0.329577
+0.6255 0.322554
+0.626 0.313636
+0.6265 0.302851
+0.627 0.290249
+0.6275 0.275878
+0.628 0.259807
+0.6285 0.242113
+0.629 0.222877
+0.6295 0.2022
+0.63 0.18018
+0.6305 0.156932
+0.631 0.132581
+0.6315 0.107248
+0.632 0.0810733
+0.6325 0.0541978
+0.633 0.0267653
+0.6335 -0.00107051
+0.634 -0.0291593
+0.6345 -0.0573394
+0.635 -0.0854513
+0.6355 -0.113337
+0.636 -0.140834
+0.6365 -0.167785
+0.637 -0.19403
+0.6375 -0.219411
+0.638 -0.243779
+0.6385 -0.266984
+0.639 -0.288886
+0.6395 -0.309349
+0.64 -0.328238
+0.6405 -0.345438
+0.641 -0.360832
+0.6415 -0.374318
+0.642 -0.385802
+0.6425 -0.395198
+0.643 -0.402438
+0.6435 -0.407459
+0.644 -0.410213
+0.6445 -0.410665
+0.645 -0.408791
+0.6455 -0.40458
+0.646 -0.398036
+0.6465 -0.389178
+0.647 -0.378031
+0.6475 -0.364643
+0.648 -0.349066
+0.6485 -0.33137
+0.649 -0.311641
+0.6495 -0.289968
+0.65 -0.266463
+0.6505 -0.241235
+0.651 -0.21442
+0.6515 -0.186154
+0.652 -0.156582
+0.6525 -0.125868
+0.653 -0.0941679
+0.6535 -0.0616588
+0.654 -0.0285188
+0.6545 0.00507432
+0.655 0.0389249
+0.6555 0.072853
+0.656 0.10666
+0.6565 0.140152
+0.657 0.17314
+0.6575 0.205431
+0.658 0.236831
+0.6585 0.267161
+0.659 0.296234
+0.6595 0.323877
+0.66 0.349921
+0.6605 0.374199
+0.661 0.396566
+0.6615 0.416873
+0.662 0.434989
+0.6625 0.450793
+0.663 0.464172
+0.6635 0.475035
+0.664 0.483295
+0.6645 0.488885
+0.665 0.49175
+0.6655 0.491851
+0.666 0.489164
+0.6665 0.483681
+0.667 0.47541
+0.6675 0.464374
+0.668 0.450615
+0.6685 0.434184
+0.669 0.415155
+0.6695 0.393617
+0.67 0.369666
+0.6705 0.343425
+0.671 0.315015
+0.6715 0.284587
+0.672 0.252296
+0.6725 0.218306
+0.673 0.182804
+0.6735 0.145969
+0.674 0.108006
+0.6745 0.0691231
+0.675 0.0295283
+0.6755 -0.0105549
+0.676 -0.0509088
+0.6765 -0.0913003
+0.677 -0.1315
+0.6775 -0.171283
+0.678 -0.210415
+0.6785 -0.248673
+0.679 -0.285832
+0.6795 -0.321666
+0.68 -0.355968
+0.6805 -0.388526
+0.681 -0.419146
+0.6815 -0.447636
+0.682 -0.473813
+0.6825 -0.497519
+0.683 -0.518593
+0.6835 -0.536893
+0.684 -0.552299
+0.6845 -0.564696
+0.685 -0.573993
+0.6855 -0.58011
+0.686 -0.582988
+0.6865 -0.582586
+0.687 -0.57888
+0.6875 -0.571864
+0.688 -0.561552
+0.6885 -0.547981
+0.689 -0.531196
+0.6895 -0.511273
+0.69 -0.488295
+0.6905 -0.462372
+0.691 -0.433632
+0.6915 -0.402208
+0.692 -0.368267
+0.6925 -0.331972
+0.693 -0.293516
+0.6935 -0.253107
+0.694 -0.210947
+0.6945 -0.167271
+0.695 -0.122314
+0.6955 -0.0763184
+0.696 -0.0295412
+0.6965 0.017765
+0.697 0.0653285
+0.6975 0.112881
+0.698 0.160158
+0.6985 0.206883
+0.699 0.252793
+0.6995 0.29762
+0.7 0.341094
+0.7005 0.382966
+0.701 0.422982
+0.7015 0.460905
+0.702 0.496502
+0.7025 0.529549
+0.703 0.559849
+0.7035 0.5872
+0.704 0.611431
+0.7045 0.63238
+0.705 0.649901
+0.7055 0.663873
+0.706 0.674188
+0.7065 0.680762
+0.707 0.683529
+0.7075 0.682445
+0.708 0.677489
+0.7085 0.66866
+0.709 0.655982
+0.7095 0.639494
+0.71 0.619269
+0.7105 0.595386
+0.711 0.567958
+0.7115 0.537121
+0.712 0.503014
+0.7125 0.465818
+0.713 0.42571
+0.7135 0.382906
+0.714 0.337628
+0.7145 0.290109
+0.715 0.240615
+0.7155 0.189396
+0.716 0.136743
+0.7165 0.0829431
+0.717 0.0282854
+0.7175 -0.0269121
+0.718 -0.082357
+0.7185 -0.137725
+0.719 -0.192702
+0.7195 -0.246978
+0.72 -0.300241
+0.7205 -0.35217
+0.721 -0.402478
+0.7215 -0.450854
+0.722 -0.49702
+0.7225 -0.540695
+0.723 -0.581609
+0.7235 -0.61952
+0.724 -0.654184
+0.7245 -0.685388
+0.725 -0.712929
+0.7255 -0.736621
+0.726 -0.756311
+0.7265 -0.771853
+0.727 -0.783135
+0.7275 -0.790062
+0.728 -0.792565
+0.7285 -0.790599
+0.729 -0.784146
+0.7295 -0.773211
+0.73 -0.757825
+0.7305 -0.73805
+0.731 -0.71396
+0.7315 -0.685668
+0.732 -0.653309
+0.7325 -0.617031
+0.733 -0.577025
+0.7335 -0.533478
+0.734 -0.486624
+0.7345 -0.436707
+0.735 -0.38398
+0.7355 -0.328739
+0.736 -0.271263
+0.7365 -0.211874
+0.737 -0.150897
+0.7375 -0.0886603
+0.738 -0.0255159
+0.7385 0.0381943
+0.739 0.102103
+0.7395 0.165849
+0.74 0.229077
+0.7405 0.291418
+0.741 0.352519
+0.7415 0.412025
+0.742 0.469581
+0.7425 0.524855
+0.743 0.577514
+0.7435 0.627249
+0.744 0.673757
+0.7445 0.716746
+0.745 0.755962
+0.7455 0.791153
+0.746 0.822087
+0.7465 0.848573
+0.747 0.870424
+0.7475 0.887493
+0.748 0.89965
+0.7485 0.906793
+0.749 0.908853
+0.7495 0.905786
+0.75 0.897576
+0.7505 0.884236
+0.751 0.865815
+0.7515 0.842379
+0.752 0.814037
+0.7525 0.780909
+0.753 0.743159
+0.7535 0.700979
+0.754 0.654566
+0.7545 0.604174
+0.755 0.550046
+0.7555 0.492474
+0.756 0.431774
+0.7565 0.368251
+0.757 0.302261
+0.7575 0.234163
+0.758 0.164323
+0.7585 0.0931338
+0.759 0.0209795
+0.7595 -0.0517257
+0.76 -0.124573
+0.7605 -0.197158
+0.761 -0.269061
+0.7615 -0.339877
+0.762 -0.409198
+0.7625 -0.476612
+0.763 -0.541736
+0.7635 -0.604181
+0.764 -0.663583
+0.7645 -0.719588
+0.765 -0.771847
+0.7655 -0.820057
+0.766 -0.86391
+0.7665 -0.903139
+0.767 -0.937492
+0.7675 -0.966741
+0.768 -0.9907
+0.7685 -1.00919
+0.769 -1.02209
+0.7695 -1.02929
+0.77 -1.0307
+0.7705 -1.0263
+0.771 -1.01607
+0.7715 -1.00004
+0.772 -0.978266
+0.7725 -0.950838
+0.773 -0.917875
+0.7735 -0.879534
+0.774 -0.836011
+0.7745 -0.787509
+0.775 -0.734289
+0.7755 -0.67661
+0.776 -0.614785
+0.7765 -0.549141
+0.777 -0.480018
+0.7775 -0.407807
+0.778 -0.332877
+0.7785 -0.255652
+0.779 -0.176557
+0.7795 -0.0960186
+0.78 -0.0145043
+0.7805 0.0675539
+0.781 0.149678
+0.7815 0.231402
+0.782 0.312271
+0.7825 0.391821
+0.783 0.469578
+0.7835 0.545116
+0.784 0.617976
+0.7845 0.687743
+0.785 0.754002
+0.7855 0.816349
+0.786 0.874426
+0.7865 0.927868
+0.787 0.976356
+0.7875 1.01959
+0.788 1.05728
+0.7885 1.08921
+0.789 1.11515
+0.7895 1.13492
+0.79 1.14839
+0.7905 1.15544
+0.791 1.15599
+0.7915 1.15002
+0.792 1.13752
+0.7925 1.11853
+0.793 1.09312
+0.7935 1.0614
+0.794 1.02352
+0.7945 0.979661
+0.795 0.930041
+0.7955 0.874917
+0.796 0.814559
+0.7965 0.749293
+0.797 0.679468
+0.7975 0.605441
+0.798 0.527627
+0.7985 0.44643
+0.799 0.362298
+0.7995 0.275707
+0.8 0.187114
+0.8005 0.0970296
+0.801 0.00593733
+0.8015 -0.0856452
+0.802 -0.177186
+0.8025 -0.268193
+0.803 -0.358125
+0.8035 -0.446487
+0.804 -0.532762
+0.8045 -0.616443
+0.805 -0.697062
+0.8055 -0.774127
+0.806 -0.847206
+0.8065 -0.915853
+0.807 -0.979653
+0.8075 -1.03824
+0.808 -1.09124
+0.8085 -1.13833
+0.809 -1.17921
+0.8095 -1.21364
+0.81 -1.24137
+0.8105 -1.26223
+0.811 -1.27605
+0.8115 -1.28273
+0.812 -1.28221
+0.8125 -1.27443
+0.813 -1.25943
+0.8135 -1.23724
+0.814 -1.20796
+0.8145 -1.17173
+0.815 -1.1287
+0.8155 -1.07911
+0.816 -1.02319
+0.8165 -0.961235
+0.817 -0.893574
+0.8175 -0.820547
+0.818 -0.742554
+0.8185 -0.660021
+0.819 -0.573377
+0.8195 -0.483101
+0.82 -0.389702
+0.8205 -0.293667
+0.821 -0.195555
+0.8215 -0.0958884
+0.822 0.00476546
+0.8225 0.105831
+0.823 0.206761
+0.8235 0.306957
+0.824 0.405877
+0.8245 0.50294
+0.825 0.59758
+0.8255 0.689271
+0.826 0.777462
+0.8265 0.86166
+0.827 0.941356
+0.8275 1.01608
+0.828 1.08539
+0.8285 1.14887
+0.829 1.20614
+0.8295 1.25685
+0.83 1.30068
+0.8305 1.33735
+0.831 1.36663
+0.8315 1.38831
+0.832 1.40226
+0.8325 1.40834
+0.833 1.4065
+0.8335 1.39672
+0.834 1.37901
+0.8345 1.35344
+0.835 1.32013
+0.8355 1.27922
+0.836 1.23093
+0.8365 1.1755
+0.837 1.11319
+0.8375 1.04436
+0.838 0.969344
+0.8385 0.888553
+0.839 0.802429
+0.8395 0.71142
+0.84 0.616039
+0.8405 0.51679
+0.841 0.414224
+0.8415 0.308925
+0.842 0.201454
+0.8425 0.0924322
+0.843 -0.0175529
+0.8435 -0.127874
+0.844 -0.23789
+0.8445 -0.347009
+0.845 -0.454593
+0.8455 -0.560018
+0.846 -0.662701
+0.8465 -0.762031
+0.847 -0.857454
+0.8475 -0.948402
+0.848 -1.03434
+0.8485 -1.11477
+0.849 -1.18921
+0.8495 -1.25723
+0.85 -1.31841
+0.8505 -1.37238
+0.851 -1.41881
+0.8515 -1.4574
+0.852 -1.48792
+0.8525 -1.51015
+0.853 -1.52394
+0.8535 -1.52919
+0.854 -1.52583
+0.8545 -1.51384
+0.855 -1.49327
+0.8555 -1.46421
+0.856 -1.42677
+0.8565 -1.38115
+0.857 -1.32758
+0.8575 -1.26632
+0.858 -1.1977
+0.8585 -1.12207
+0.859 -1.03985
+0.8595 -0.951477
+0.86 -0.857418
+0.8605 -0.758201
+0.861 -0.654351
+0.8615 -0.546444
+0.862 -0.435094
+0.8625 -0.320894
+0.863 -0.204502
+0.8635 -0.0865447
+0.864 0.0323067
+0.8645 0.151363
+0.865 0.269987
+0.8655 0.387474
+0.866 0.503183
+0.8665 0.616442
+0.867 0.726591
+0.8675 0.833022
+0.868 0.935092
+0.8685 1.03224
+0.869 1.12388
+0.8695 1.20948
+0.87 1.28854
+0.8705 1.36059
+0.871 1.42519
+0.8715 1.48197
+0.872 1.53057
+0.8725 1.5707
+0.873 1.60209
+0.8735 1.62455
+0.874 1.63792
+0.8745 1.64209
+0.875 1.63701
+0.8755 1.62268
+0.876 1.59916
+0.8765 1.56655
+0.877 1.525
+0.8775 1.47472
+0.878 1.41597
+0.8785 1.34906
+0.879 1.27433
+0.8795 1.1922
+0.88 1.10309
+0.8805 1.00748
+0.881 0.905927
+0.8815 0.798947
+0.882 0.687141
+0.8825 0.571147
+0.883 0.451574
+0.8835 0.329119
+0.884 0.204439
+0.8845 0.0782435
+0.885 -0.048745
+0.8855 -0.17584
+0.886 -0.302289
+0.8865 -0.427414
+0.887 -0.55048
+0.8875 -0.670779
+0.888 -0.787646
+0.8885 -0.900389
+0.889 -1.00838
+0.8895 -1.11099
+0.89 -1.2076
+0.8905 -1.29769
+0.891 -1.38069
+0.8915 -1.45615
+0.892 -1.5236
+0.8925 -1.58263
+0.893 -1.63291
+0.8935 -1.67411
+0.894 -1.70599
+0.8945 -1.72833
+0.895 -1.74098
+0.8955 -1.74386
+0.896 -1.73691
+0.8965 -1.72015
+0.897 -1.69365
+0.8975 -1.65754
+0.898 -1.61198
+0.8985 -1.55722
+0.899 -1.49355
+0.8995 -1.42129
+0.9 -1.34085
+0.9005 -1.25264
+0.901 -1.15714
+0.9015 -1.0549
+0.902 -0.946445
+0.9025 -0.832403
+0.903 -0.713377
+0.9035 -0.590041
+0.904 -0.463096
+0.9045 -0.333221
+0.905 -0.201171
+0.9055 -0.0676599
+0.906 0.06655
+0.9065 0.200685
+0.907 0.334018
+0.9075 0.465778
+0.908 0.595203
+0.9085 0.721587
+0.909 0.844177
+0.9095 0.962304
+0.91 1.07527
+0.9105 1.18243
+0.911 1.28316
+0.9115 1.37688
+0.912 1.46306
+0.9125 1.54118
+0.913 1.61078
+0.9135 1.67146
+0.914 1.72285
+0.9145 1.76464
+0.915 1.79657
+0.9155 1.81845
+0.916 1.83012
+0.9165 1.83151
+0.917 1.82257
+0.9175 1.80335
+0.918 1.77392
+0.9185 1.73444
+0.919 1.6851
+0.9195 1.62617
+0.92 1.55795
+0.9205 1.48082
+0.921 1.39519
+0.9215 1.30152
+0.922 1.20035
+0.9225 1.0922
+0.923 0.977703
+0.9235 0.857461
+0.924 0.732157
+0.9245 0.602506
+0.925 0.469198
+0.9255 0.333013
+0.926 0.19468
+0.9265 0.0549945
+0.927 -0.085242
+0.9275 -0.22527
+0.928 -0.364266
+0.9285 -0.501477
+0.929 -0.636108
+0.9295 -0.767377
+0.93 -0.89457
+0.9305 -1.01693
+0.931 -1.13379
+0.9315 -1.24446
+0.932 -1.3483
+0.9325 -1.44473
+0.933 -1.53318
+0.9335 -1.61313
+0.934 -1.68414
+0.9345 -1.74577
+0.935 -1.79767
+0.9355 -1.83952
+0.936 -1.87108
+0.9365 -1.89215
+0.937 -1.90259
+0.9375 -1.90233
+0.938 -1.89135
+0.9385 -1.8697
+0.939 -1.83749
+0.9395 -1.79487
+0.94 -1.74208
+0.9405 -1.67939
+0.941 -1.60715
+0.9415 -1.52575
+0.942 -1.43564
+0.9425 -1.33731
+0.943 -1.2313
+0.9435 -1.11821
+0.944 -0.998652
+0.9445 -0.8733
+0.945 -0.74287
+0.9455 -0.608061
+0.946 -0.46966
+0.9465 -0.328409
+0.947 -0.185118
+0.9475 -0.0406129
+0.948 0.104329
+0.9485 0.248854
+0.949 0.39218
+0.9495 0.53348
+0.95 0.671937
+0.9505 0.8068
+0.951 0.937269
+0.9515 1.06263
+0.952 1.18217
+0.9525 1.29517
+0.953 1.40103
+0.9535 1.4991
+0.954 1.58886
+0.9545 1.66978
+0.955 1.74137
+0.9555 1.80324
+0.956 1.85502
+0.9565 1.89642
+0.957 1.92718
+0.9575 1.94711
+0.958 1.95611
+0.9585 1.95409
+0.959 1.94107
+0.9595 1.9171
+0.96 1.88232
+0.9605 1.83689
+0.961 1.78108
+0.9615 1.71518
+0.962 1.63956
+0.9625 1.55464
+0.963 1.46088
+0.9635 1.3588
+0.964 1.24899
+0.9645 1.13203
+0.965 1.00861
+0.9655 0.879391
+0.966 0.745105
+0.9665 0.606525
+0.967 0.464396
+0.9675 0.319552
+0.968 0.172774
+0.9685 0.0249056
+0.969 -0.123203
+0.9695 -0.270749
+0.97 -0.416884
+0.9705 -0.560763
+0.971 -0.701608
+0.9715 -0.838588
+0.972 -0.97096
+0.9725 -1.09796
+0.973 -1.21884
+0.9735 -1.33297
+0.974 -1.43964
+0.9745 -1.5383
+0.975 -1.62835
+0.9755 -1.70928
+0.976 -1.78065
+0.9765 -1.84203
+0.977 -1.89308
+0.9775 -1.9335
+0.978 -1.96305
+0.9785 -1.98156
+0.979 -1.98893
+0.9795 -1.98511
+0.98 -1.97011
+0.9805 -1.94401
+0.981 -1.90695
+0.9815 -1.85913
+0.982 -1.80084
+0.9825 -1.73237
+0.983 -1.65412
+0.9835 -1.56653
+0.984 -1.47007
+0.9845 -1.36531
+0.985 -1.25282
+0.9855 -1.13324
+0.986 -1.00722
+0.9865 -0.87549
+0.987 -0.738802
+0.9875 -0.597895
+0.988 -0.453594
+0.9885 -0.306679
+0.989 -0.157996
+0.9895 -0.00839989
+0.99 0.141301
+0.9905 0.290225
+0.991 0.437569
+0.9915 0.582483
+0.992 0.724131
+0.9925 0.861749
+0.993 0.994525
+0.9935 1.12174
+0.994 1.24266
+0.9945 1.3566
+0.995 1.46292
+0.9955 1.56102
+0.996 1.65034
+0.9965 1.73039
+0.997 1.80069
+0.9975 1.86087
+0.998 1.91058
+0.9985 1.94953
+0.999 1.97752
+0.9995 1.99437
+1 2
+1.0005 1.99437
+1.001 1.97752
+1.0015 1.94953
+1.002 1.91058
+1.0025 1.86086
+1.003 1.80069
+1.0035 1.73039
+1.004 1.65035
+1.0045 1.56101
+1.005 1.46292
+1.0055 1.35661
+1.006 1.24265
+1.0065 1.12174
+1.007 0.994541
+1.0075 0.861733
+1.008 0.724131
+1.0085 0.582483
+1.009 0.437587
+1.0095 0.290225
+1.01 0.141301
+1.0105 -0.00838203
+1.011 -0.158014
+1.0115 -0.306679
+1.012 -0.453577
+1.0125 -0.597912
+1.013 -0.738802
+1.0135 -0.87549
+1.014 -1.00724
+1.0145 -1.13324
+1.015 -1.25282
+1.0155 -1.3653
+1.016 -1.47008
+1.0165 -1.56653
+1.017 -1.65411
+1.0175 -1.73238
+1.018 -1.80084
+1.0185 -1.85913
+1.019 -1.90695
+1.0195 -1.94401
+1.02 -1.97011
+1.0205 -1.98511
+1.021 -1.98893
+1.0215 -1.98156
+1.022 -1.96305
+1.0225 -1.93349
+1.023 -1.89308
+1.0235 -1.84203
+1.024 -1.78064
+1.0245 -1.70928
+1.025 -1.62835
+1.0255 -1.53829
+1.026 -1.43964
+1.0265 -1.33297
+1.027 -1.21886
+1.0275 -1.09794
+1.028 -0.97096
+1.0285 -0.838605
+1.029 -0.701591
+1.0295 -0.560763
+1.03 -0.416884
+1.0305 -0.270731
+1.031 -0.123203
+1.0315 0.0249056
+1.032 0.172756
+1.0325 0.319552
+1.033 0.464396
+1.0335 0.606508
+1.034 0.745122
+1.0345 0.879391
+1.035 1.0086
+1.0355 1.13205
+1.036 1.24899
+1.0365 1.3588
+1.037 1.46087
+1.0375 1.55464
+1.038 1.63956
+1.0385 1.71518
+1.039 1.78108
+1.0395 1.83689
+1.04 1.88231
+1.0405 1.91711
+1.041 1.94107
+1.0415 1.95409
+1.042 1.95611
+1.0425 1.94711
+1.043 1.92718
+1.0435 1.89642
+1.044 1.85502
+1.0445 1.80324
+1.045 1.74138
+1.0455 1.66977
+1.046 1.58886
+1.0465 1.49911
+1.047 1.40101
+1.0475 1.29517
+1.048 1.18217
+1.0485 1.06265
+1.049 0.937269
+1.0495 0.8068
+1.05 0.671954
+1.0505 0.533463
+1.051 0.39218
+1.0515 0.24887
+1.052 0.104311
+1.0525 -0.0406129
+1.053 -0.185118
+1.0535 -0.328425
+1.054 -0.46966
+1.0545 -0.608061
+1.055 -0.742855
+1.0555 -0.873315
+1.056 -0.998652
+1.0565 -1.1182
+1.057 -1.23131
+1.0575 -1.33731
+1.058 -1.43563
+1.0585 -1.52576
+1.059 -1.60715
+1.0595 -1.67939
+1.06 -1.74207
+1.0605 -1.79487
+1.061 -1.83749
+1.0615 -1.8697
+1.062 -1.89135
+1.0625 -1.90233
+1.063 -1.90259
+1.0635 -1.89215
+1.064 -1.87108
+1.0645 -1.83952
+1.065 -1.79766
+1.0655 -1.74577
+1.066 -1.68414
+1.0665 -1.61314
+1.067 -1.53317
+1.0675 -1.44473
+1.068 -1.34831
+1.0685 -1.24445
+1.069 -1.13379
+1.0695 -1.01695
+1.07 -0.894556
+1.0705 -0.767377
+1.071 -0.636108
+1.0715 -0.501493
+1.072 -0.364266
+1.0725 -0.22527
+1.073 -0.0852581
+1.0735 0.0550105
+1.074 0.19468
+1.0745 0.332995
+1.075 0.469215
+1.0755 0.602506
+1.076 0.732157
+1.0765 0.857477
+1.077 0.977703
+1.0775 1.0922
+1.078 1.20033
+1.0785 1.30153
+1.079 1.39519
+1.0795 1.48081
+1.08 1.55796
+1.0805 1.62617
+1.081 1.6851
+1.0815 1.73444
+1.082 1.77392
+1.0825 1.80335
+1.083 1.82257
+1.0835 1.83151
+1.084 1.83012
+1.0845 1.81845
+1.085 1.79657
+1.0855 1.76464
+1.086 1.72285
+1.0865 1.67145
+1.087 1.61078
+1.0875 1.54118
+1.088 1.46305
+1.0885 1.37688
+1.089 1.28316
+1.0895 1.18244
+1.09 1.07526
+1.0905 0.962304
+1.091 0.844192
+1.0915 0.721572
+1.092 0.595203
+1.0925 0.465778
+1.093 0.334002
+1.0935 0.200685
+1.094 0.06655
+1.0945 -0.0676429
+1.095 -0.201171
+1.0955 -0.333221
+1.096 -0.463082
+1.0965 -0.590057
+1.097 -0.713377
+1.0975 -0.832389
+1.098 -0.946458
+1.0985 -1.0549
+1.099 -1.15714
+1.0995 -1.25262
+1.1 -1.34085
+1.1005 -1.42129
+1.101 -1.49354
+1.1015 -1.55723
+1.102 -1.61198
+1.1025 -1.65753
+1.103 -1.69365
+1.1035 -1.72015
+1.104 -1.73691
+1.1045 -1.74386
+1.105 -1.74098
+1.1055 -1.72833
+1.106 -1.70599
+1.1065 -1.67411
+1.107 -1.63291
+1.1075 -1.58264
+1.108 -1.52359
+1.1085 -1.45615
+1.109 -1.3807
+1.1095 -1.29768
+1.11 -1.2076
+1.1105 -1.11099
+1.111 -1.00839
+1.1115 -0.900389
+1.112 -0.787646
+1.1125 -0.670794
+1.113 -0.550468
+1.1135 -0.427414
+1.114 -0.302305
+1.1145 -0.175824
+1.115 -0.048745
+1.1155 0.0782435
+1.116 0.204455
+1.1165 0.329119
+1.117 0.451574
+1.1175 0.571132
+1.118 0.687155
+1.1185 0.798947
+1.119 0.905916
+1.1195 1.0075
+1.12 1.10309
+1.1205 1.19219
+1.121 1.27434
+1.1215 1.34906
+1.122 1.41597
+1.1225 1.47471
+1.123 1.525
+1.1235 1.56655
+1.124 1.59916
+1.1245 1.62268
+1.125 1.63701
+1.1255 1.64209
+1.126 1.63791
+1.1265 1.62455
+1.127 1.60209
+1.1275 1.57069
+1.128 1.53057
+1.1285 1.48197
+1.129 1.4252
+1.1295 1.36058
+1.13 1.28854
+1.1305 1.20949
+1.131 1.12387
+1.1315 1.03224
+1.132 0.935104
+1.1325 0.833009
+1.133 0.726591
+1.1335 0.616442
+1.134 0.503198
+1.1345 0.387474
+1.135 0.269987
+1.1355 0.151378
+1.136 0.0322916
+1.1365 -0.0865447
+1.137 -0.20449
+1.1375 -0.320908
+1.138 -0.435094
+1.1385 -0.546444
+1.139 -0.654361
+1.1395 -0.758201
+1.14 -0.857418
+1.1405 -0.951468
+1.141 -1.03986
+1.1415 -1.12207
+1.142 -1.19769
+1.1425 -1.26632
+1.143 -1.32758
+1.1435 -1.38115
+1.144 -1.42678
+1.1445 -1.46421
+1.145 -1.49327
+1.1455 -1.51384
+1.146 -1.52583
+1.1465 -1.52919
+1.147 -1.52395
+1.1475 -1.51015
+1.148 -1.48792
+1.1485 -1.4574
+1.149 -1.4188
+1.1495 -1.37238
+1.15 -1.31841
+1.1505 -1.25722
+1.151 -1.18921
+1.1515 -1.11477
+1.152 -1.03435
+1.1525 -0.948391
+1.153 -0.857454
+1.1535 -0.762043
+1.154 -0.662691
+1.1545 -0.560018
+1.155 -0.454593
+1.1555 -0.346996
+1.156 -0.23789
+1.1565 -0.127874
+1.157 -0.0175669
+1.1575 0.0924322
+1.158 0.201454
+1.1585 0.308915
+1.159 0.414237
+1.1595 0.51679
+1.16 0.616027
+1.1605 0.711432
+1.161 0.802429
+1.1615 0.888553
+1.162 0.969336
+1.1625 1.04436
+1.163 1.11319
+1.1635 1.17549
+1.164 1.23094
+1.1645 1.27922
+1.165 1.32012
+1.1655 1.35344
+1.166 1.37901
+1.1665 1.39672
+1.167 1.40651
+1.1675 1.40834
+1.168 1.40226
+1.1685 1.38832
+1.169 1.36663
+1.1695 1.33735
+1.17 1.30068
+1.1705 1.25684
+1.171 1.20614
+1.1715 1.14888
+1.172 1.08538
+1.1725 1.01608
+1.173 0.941356
+1.1735 0.861668
+1.174 0.777462
+1.1745 0.689271
+1.175 0.597592
+1.1755 0.50293
+1.176 0.405877
+1.1765 0.306969
+1.177 0.206749
+1.1775 0.105831
+1.178 0.00476546
+1.1785 -0.0959011
+1.179 -0.195555
+1.1795 -0.293667
+1.18 -0.38969
+1.1805 -0.483112
+1.181 -0.573377
+1.1815 -0.660012
+1.182 -0.742564
+1.1825 -0.820547
+1.183 -0.893564
+1.1835 -0.961242
+1.184 -1.02319
+1.1845 -1.07911
+1.185 -1.1287
+1.1855 -1.17173
+1.186 -1.20796
+1.1865 -1.23724
+1.187 -1.25943
+1.1875 -1.27443
+1.188 -1.28221
+1.1885 -1.28273
+1.189 -1.27605
+1.1895 -1.26223
+1.19 -1.24137
+1.1905 -1.21364
+1.191 -1.17921
+1.1915 -1.13833
+1.192 -1.09123
+1.1925 -1.03824
+1.193 -0.979661
+1.1935 -0.915846
+1.194 -0.847206
+1.1945 -0.774136
+1.195 -0.697052
+1.1955 -0.616443
+1.196 -0.532762
+1.1965 -0.446498
+1.197 -0.358125
+1.1975 -0.268193
+1.198 -0.177197
+1.1985 -0.0856335
+1.199 0.00593733
+1.1995 0.0970204
+1.2 0.187126
+1.2005 0.275707
+1.201 0.362298
+1.2015 0.446438
+1.202 0.527627
+1.2025 0.605441
+1.203 0.67946
+1.2035 0.749302
+1.204 0.814559
+1.2045 0.874909
+1.205 0.930046
+1.2055 0.979661
+1.206 1.02352
+1.2065 1.0614
+1.207 1.09312
+1.2075 1.11853
+1.208 1.13752
+1.2085 1.15002
+1.209 1.15599
+1.2095 1.15544
+1.21 1.14839
+1.2105 1.13492
+1.211 1.11515
+1.2115 1.0892
+1.212 1.05728
+1.2125 1.01959
+1.213 0.976351
+1.2135 0.927868
+1.214 0.874426
+1.2145 0.816358
+1.215 0.753996
+1.2155 0.687743
+1.216 0.617984
+1.2165 0.545109
+1.217 0.469578
+1.2175 0.391821
+1.218 0.312263
+1.2185 0.231402
+1.219 0.149678
+1.2195 0.0675623
+1.22 -0.0145043
+1.2205 -0.0960186
+1.221 -0.176549
+1.2215 -0.25566
+1.222 -0.332877
+1.2225 -0.407799
+1.223 -0.480029
+1.2235 -0.549141
+1.224 -0.614785
+1.2245 -0.676604
+1.225 -0.734289
+1.2255 -0.787509
+1.226 -0.836007
+1.2265 -0.879541
+1.227 -0.917875
+1.2275 -0.950834
+1.228 -0.97827
+1.2285 -1.00004
+1.229 -1.01607
+1.2295 -1.0263
+1.23 -1.0307
+1.2305 -1.02929
+1.231 -1.02209
+1.2315 -1.00919
+1.232 -0.9907
+1.2325 -0.966745
+1.233 -0.937489
+1.2335 -0.903139
+1.234 -0.863915
+1.2345 -0.820053
+1.235 -0.771847
+1.2355 -0.719588
+1.236 -0.663592
+1.2365 -0.604181
+1.237 -0.541736
+1.2375 -0.476619
+1.238 -0.409191
+1.2385 -0.339877
+1.239 -0.269068
+1.2395 -0.197151
+1.24 -0.124573
+1.2405 -0.0517257
+1.241 0.0209906
+1.2415 0.0931338
+1.242 0.164323
+1.2425 0.234156
+1.243 0.302268
+1.2435 0.368251
+1.244 0.431768
+1.2445 0.492483
+1.245 0.550046
+1.2455 0.604168
+1.246 0.654574
+1.2465 0.700979
+1.247 0.743159
+1.2475 0.780906
+1.248 0.814037
+1.2485 0.842379
+1.249 0.865813
+1.2495 0.884239
+1.25 0.897576
+1.2505 0.905785
+1.251 0.908853
+1.2515 0.906793
+1.252 0.89965
+1.2525 0.887492
+1.253 0.870424
+1.2535 0.848573
+1.254 0.822092
+1.2545 0.791149
+1.255 0.755962
+1.2555 0.716752
+1.256 0.673753
+1.2565 0.627249
+1.257 0.57752
+1.2575 0.52485
+1.258 0.469581
+1.2585 0.412025
+1.259 0.352528
+1.2595 0.291418
+1.26 0.229077
+1.2605 0.165856
+1.261 0.102097
+1.2615 0.0381943
+1.262 -0.0255094
+1.2625 -0.0886667
+1.263 -0.150897
+1.2635 -0.211874
+1.264 -0.271271
+1.2645 -0.328739
+1.265 -0.38398
+1.2655 -0.436701
+1.266 -0.486629
+1.2665 -0.533478
+1.267 -0.57702
+1.2675 -0.617037
+1.268 -0.653309
+1.2685 -0.685668
+1.269 -0.713963
+1.2695 -0.73805
+1.27 -0.757825
+1.2705 -0.77321
+1.271 -0.784146
+1.2715 -0.790599
+1.272 -0.792564
+1.2725 -0.790061
+1.273 -0.783135
+1.2735 -0.771855
+1.274 -0.756309
+1.2745 -0.736621
+1.275 -0.712929
+1.2755 -0.685385
+1.276 -0.654184
+1.2765 -0.61952
+1.277 -0.581615
+1.2775 -0.540691
+1.278 -0.49702
+1.2785 -0.450859
+1.279 -0.402473
+1.2795 -0.35217
+1.28 -0.300241
+1.2805 -0.246972
+1.281 -0.192702
+1.2815 -0.137725
+1.282 -0.0823626
+1.2825 -0.0269121
+1.283 0.0282854
+1.2835 0.0829376
+1.284 0.136749
+1.2845 0.189396
+1.285 0.24061
+1.2855 0.290116
+1.286 0.337628
+1.2865 0.382906
+1.287 0.425706
+1.2875 0.465818
+1.288 0.503014
+1.2885 0.537117
+1.289 0.567963
+1.2895 0.595386
+1.29 0.619265
+1.2905 0.639497
+1.291 0.655982
+1.2915 0.66866
+1.292 0.67749
+1.2925 0.682445
+1.293 0.683529
+1.2935 0.680762
+1.294 0.674188
+1.2945 0.663873
+1.295 0.649903
+1.2955 0.632378
+1.296 0.611431
+1.2965 0.587203
+1.297 0.559846
+1.2975 0.529549
+1.298 0.496502
+1.2985 0.46091
+1.299 0.422982
+1.2995 0.382966
+1.3 0.341098
+1.3005 0.297615
+1.301 0.252793
+1.3015 0.206888
+1.302 0.160153
+1.3025 0.112881
+1.303 0.0653285
+1.3035 0.0177578
+1.304 -0.0295412
+1.3045 -0.0763184
+1.305 -0.12231
+1.3055 -0.167275
+1.306 -0.210947
+1.3065 -0.253103
+1.307 -0.293522
+1.3075 -0.331972
+1.308 -0.368263
+1.3085 -0.402213
+1.309 -0.433632
+1.3095 -0.462372
+1.31 -0.488293
+1.3105 -0.511273
+1.311 -0.531196
+1.3115 -0.547979
+1.312 -0.561554
+1.3125 -0.571864
+1.313 -0.578879
+1.3135 -0.582586
+1.314 -0.582988
+1.3145 -0.58011
+1.315 -0.573992
+1.3155 -0.564696
+1.316 -0.552299
+1.3165 -0.536896
+1.317 -0.518591
+1.3175 -0.497519
+1.318 -0.473817
+1.3185 -0.447633
+1.319 -0.419146
+1.3195 -0.38853
+1.32 -0.355965
+1.3205 -0.321666
+1.321 -0.285832
+1.3215 -0.248678
+1.322 -0.210415
+1.3225 -0.171283
+1.323 -0.131504
+1.3235 -0.0912962
+1.324 -0.0509088
+1.3245 -0.010559
+1.325 0.0295323
+1.3255 0.0691231
+1.326 0.108006
+1.3265 0.145975
+1.327 0.182804
+1.3275 0.218306
+1.328 0.252293
+1.3285 0.28459
+1.329 0.315015
+1.3295 0.343422
+1.33 0.36967
+1.3305 0.393617
+1.331 0.415155
+1.3315 0.434186
+1.332 0.450615
+1.3325 0.464374
+1.333 0.475409
+1.3335 0.483681
+1.334 0.489164
+1.3345 0.491851
+1.335 0.49175
+1.3355 0.488885
+1.336 0.483296
+1.3365 0.475034
+1.337 0.464172
+1.3375 0.450793
+1.338 0.434987
+1.3385 0.416873
+1.339 0.396566
+1.3395 0.374203
+1.34 0.349919
+1.3405 0.323877
+1.341 0.296237
+1.3415 0.267158
+1.342 0.236831
+1.3425 0.205431
+1.343 0.173136
+1.3435 0.140152
+1.344 0.10666
+1.3445 0.0728565
+1.345 0.0389249
+1.3455 0.00507432
+1.346 -0.0285154
+1.3465 -0.0616621
+1.347 -0.0941679
+1.3475 -0.125865
+1.348 -0.156587
+1.3485 -0.186154
+1.349 -0.21442
+1.3495 -0.241233
+1.35 -0.266463
+1.3505 -0.289968
+1.351 -0.311639
+1.3515 -0.331373
+1.352 -0.349066
+1.3525 -0.364641
+1.353 -0.378033
+1.3535 -0.389178
+1.354 -0.398036
+1.3545 -0.404581
+1.355 -0.408791
+1.3555 -0.410665
+1.356 -0.410214
+1.3565 -0.407459
+1.357 -0.402438
+1.3575 -0.395199
+1.358 -0.385801
+1.3585 -0.374318
+1.359 -0.360833
+1.3595 -0.345436
+1.36 -0.328238
+1.3605 -0.309349
+1.361 -0.28889
+1.3615 -0.266984
+1.362 -0.243779
+1.3625 -0.219413
+1.363 -0.194027
+1.3635 -0.167785
+1.364 -0.140837
+1.3645 -0.113335
+1.365 -0.0854513
+1.3655 -0.0573394
+1.366 -0.029155
+1.3665 -0.00107051
+1.367 0.0267653
+1.3675 0.0541951
+1.368 0.081076
+1.3685 0.107248
+1.369 0.132578
+1.3695 0.156935
+1.37 0.18018
+1.3705 0.202198
+1.371 0.22288
+1.3715 0.242113
+1.372 0.259807
+1.3725 0.275877
+1.373 0.290249
+1.3735 0.302851
+1.374 0.313635
+1.3745 0.322555
+1.375 0.329577
+1.3755 0.334679
+1.376 0.337853
+1.3765 0.339096
+1.377 0.338421
+1.3775 0.335848
+1.378 0.33141
+1.3785 0.325151
+1.379 0.317123
+1.3795 0.307384
+1.38 0.29601
+1.3805 0.28308
+1.381 0.268677
+1.3815 0.252901
+1.382 0.235854
+1.3825 0.217638
+1.383 0.198376
+1.3835 0.178181
+1.384 0.157178
+1.3845 0.135485
+1.385 0.113243
+1.3855 0.0905775
+1.386 0.0676144
+1.3865 0.0444974
+1.387 0.0213512
+1.3875 -0.00169693
+1.388 -0.0245075
+1.3885 -0.0469612
+1.389 -0.0689382
+1.3895 -0.0903091
+1.39 -0.110965
+1.3905 -0.130798
+1.391 -0.149706
+1.3915 -0.167583
+1.392 -0.184345
+1.3925 -0.199909
+1.393 -0.214193
+1.3935 -0.227132
+1.394 -0.238671
+1.3945 -0.248751
+1.395 -0.257333
+1.3955 -0.264384
+1.396 -0.269879
+1.3965 -0.2738
+1.397 -0.276143
+1.3975 -0.27691
+1.398 -0.276112
+1.3985 -0.273768
+1.399 -0.269907
+1.3995 -0.264566
+1.4 -0.257791
+1.4005 -0.24963
+1.401 -0.24015
+1.4015 -0.229412
+1.402 -0.217492
+1.4025 -0.204464
+1.403 -0.190419
+1.4035 -0.175444
+1.404 -0.159629
+1.4045 -0.143078
+1.405 -0.12589
+1.4055 -0.108162
+1.406 -0.0900087
+1.4065 -0.0715316
+1.407 -0.0528399
+1.4075 -0.0340354
+1.408 -0.0152348
+1.4085 0.00346174
+1.409 0.0219525
+1.4095 0.0401271
+1.41 0.0578917
+1.4105 0.075153
+1.411 0.0918109
+1.4115 0.107783
+1.412 0.122984
+1.4125 0.137342
+1.413 0.150776
+1.4135 0.163224
+1.414 0.174628
+1.4145 0.18493
+1.415 0.194085
+1.4155 0.202056
+1.416 0.208806
+1.4165 0.214311
+1.417 0.218554
+1.4175 0.221523
+1.418 0.223215
+1.4185 0.223633
+1.419 0.222789
+1.4195 0.2207
+1.42 0.217392
+1.4205 0.212893
+1.421 0.207245
+1.4215 0.200491
+1.422 0.192677
+1.4225 0.183863
+1.423 0.174107
+1.4235 0.163474
+1.424 0.152031
+1.4245 0.139855
+1.425 0.127022
+1.4255 0.113606
+1.426 0.0996952
+1.4265 0.0853719
+1.427 0.0707171
+1.4275 0.0558222
+1.428 0.0407716
+1.4285 0.0256487
+1.429 0.0105456
+1.4295 -0.00445414
+1.43 -0.0192702
+1.4305 -0.0338223
+1.431 -0.0480254
+1.4315 -0.0618046
+1.432 -0.0750923
+1.4325 -0.0878121
+1.433 -0.099901
+1.4335 -0.1113
+1.434 -0.121947
+1.4345 -0.131792
+1.435 -0.140791
+1.4355 -0.148901
+1.436 -0.156084
+1.4365 -0.16231
+1.437 -0.167557
+1.4375 -0.171803
+1.438 -0.175036
+1.4385 -0.177249
+1.439 -0.17844
+1.4395 -0.178614
+1.44 -0.17778
+1.4405 -0.175956
+1.441 -0.173161
+1.4415 -0.169423
+1.442 -0.164771
+1.4425 -0.159244
+1.443 -0.152881
+1.4435 -0.145727
+1.444 -0.137834
+1.4445 -0.129251
+1.445 -0.120034
+1.4455 -0.110245
+1.446 -0.0999452
+1.4465 -0.0891962
+1.447 -0.0780621
+1.4475 -0.0666147
+1.448 -0.0549197
+1.4485 -0.0430435
+1.449 -0.031061
+1.4495 -0.0190362
+1.45 -0.00703624
+1.4505 0.00486666
+1.451 0.0166077
+1.4515 0.0281271
+1.452 0.0393566
+1.4525 0.0502385
+1.453 0.0607141
+1.4535 0.0707331
+1.454 0.080239
+1.4545 0.089186
+1.455 0.0975316
+1.4555 0.105232
+1.456 0.112252
+1.4565 0.118563
+1.457 0.124134
+1.4575 0.128943
+1.458 0.132971
+1.4585 0.136205
+1.459 0.138635
+1.4595 0.140258
+1.46 0.141072
+1.4605 0.141083
+1.461 0.140299
+1.4615 0.138735
+1.462 0.136408
+1.4625 0.133339
+1.463 0.129555
+1.4635 0.125086
+1.464 0.119964
+1.4645 0.114225
+1.465 0.107909
+1.4655 0.10106
+1.466 0.093721
+1.4665 0.0859376
+1.467 0.0777623
+1.4675 0.0692449
+1.468 0.0604341
+1.4685 0.0513873
+1.469 0.0421565
+1.4695 0.0327961
+1.47 0.0233583
+1.4705 0.0139021
+1.471 0.00447725
+1.4715 -0.00486436
+1.472 -0.0140672
+1.4725 -0.023082
+1.473 -0.0318637
+1.4735 -0.040361
+1.474 -0.0485311
+1.4745 -0.0563309
+1.475 -0.0637239
+1.4755 -0.0706694
+1.476 -0.0771349
+1.4765 -0.0830908
+1.477 -0.0885072
+1.4775 -0.0933606
+1.478 -0.097632
+1.4785 -0.101302
+1.479 -0.104358
+1.4795 -0.106791
+1.48 -0.108593
+1.4805 -0.109762
+1.481 -0.110299
+1.4815 -0.110208
+1.482 -0.109499
+1.4825 -0.108181
+1.483 -0.106269
+1.4835 -0.103783
+1.484 -0.100741
+1.4845 -0.0971687
+1.485 -0.0930931
+1.4855 -0.088542
+1.486 -0.0835474
+1.4865 -0.0781414
+1.487 -0.0723624
+1.4875 -0.0662454
+1.488 -0.059828
+1.4885 -0.0531529
+1.489 -0.0462602
+1.4895 -0.0391887
+1.49 -0.0319838
+1.4905 -0.0246866
+1.491 -0.0173379
+1.4915 -0.00998256
+1.492 -0.00266161
+1.4925 0.00458557
+1.493 0.0117197
+1.4935 0.018699
+1.494 0.0254867
+1.4945 0.0320496
+1.495 0.03835
+1.4955 0.044357
+1.496 0.0500414
+1.4965 0.0553728
+1.497 0.060326
+1.4975 0.0648789
+1.498 0.0690109
+1.4985 0.0727022
+1.499 0.0759381
+1.4995 0.0787071
+1.5 0.0809979
+1.5005 0.082804
+1.501 0.0841215
+1.5015 0.0849485
+1.502 0.0852869
+1.5025 0.0851406
+1.503 0.0845167
+1.5035 0.0834246
+1.504 0.0818762
+1.5045 0.0798857
+1.505 0.0774705
+1.5055 0.0746493
+1.506 0.0714423
+1.5065 0.0678742
+1.507 0.0639685
+1.5075 0.0597507
+1.508 0.0552504
+1.5085 0.0504961
+1.509 0.045517
+1.5095 0.0403434
+1.51 0.0350091
+1.5105 0.0295451
+1.511 0.0239829
+1.5115 0.0183578
+1.512 0.0127003
+1.5125 0.00704203
+1.513 0.00141726
+1.5135 -0.00414326
+1.514 -0.00961118
+1.5145 -0.014954
+1.515 -0.0201444
+1.5155 -0.0251543
+1.516 -0.0299599
+1.5165 -0.0345342
+1.517 -0.0388552
+1.5175 -0.0429026
+1.518 -0.0466555
+1.5185 -0.0500969
+1.519 -0.0532128
+1.5195 -0.055988
+1.52 -0.058412
+1.5205 -0.0604755
+1.521 -0.0621721
+1.5215 -0.0634961
+1.522 -0.0644453
+1.5225 -0.0650191
+1.523 -0.065219
+1.5235 -0.065049
+1.524 -0.0645145
+1.5245 -0.0636236
+1.525 -0.0623858
+1.5255 -0.0608123
+1.526 -0.0589172
+1.5265 -0.0567147
+1.527 -0.0542215
+1.5275 -0.0514549
+1.528 -0.0484354
+1.5285 -0.0451823
+1.529 -0.0417166
+1.5295 -0.0380621
+1.53 -0.0342415
+1.5305 -0.0302771
+1.531 -0.0261952
+1.5315 -0.0220194
+1.532 -0.0177747
+1.5325 -0.0134851
+1.533 -0.00917742
+1.5335 -0.00487467
+1.534 -0.000600586
+1.5345 0.00361934
+1.535 0.00776245
+1.5355 0.011808
+1.536 0.0157324
+1.5365 0.0195159
+1.537 0.0231387
+1.5375 0.0265838
+1.538 0.0298324
+1.5385 0.0328695
+1.539 0.0356813
+1.5395 0.0382538
+1.54 0.040576
+1.5405 0.0426391
+1.541 0.0444338
+1.5415 0.0459539
+1.542 0.0471948
+1.5425 0.0481527
+1.543 0.0488265
+1.5435 0.0492159
+1.544 0.0493228
+1.5445 0.0491501
+1.545 0.0487028
+1.5455 0.0479869
+1.546 0.0470104
+1.5465 0.0457821
+1.547 0.0443122
+1.5475 0.0426129
+1.548 0.0406963
+1.5485 0.0385765
+1.549 0.0362676
+1.5495 0.0337865
+1.55 0.0311486
+1.5505 0.0283705
+1.551 0.025471
+1.5515 0.0224679
+1.552 0.0193784
+1.5525 0.0162226
+1.553 0.0130187
+1.5535 0.00978465
+1.554 0.00654057
+1.5545 0.00330456
+1.555 9.41526e-05
+1.5555 -0.00307319
+1.556 -0.00617889
+1.5565 -0.00920658
+1.557 -0.0121414
+1.5575 -0.0149667
+1.558 -0.0176684
+1.5585 -0.0202337
+1.559 -0.0226488
+1.5595 -0.0249024
+1.56 -0.0269846
+1.5605 -0.0288861
+1.561 -0.0305979
+1.5615 -0.0321132
+1.562 -0.0334268
+1.5625 -0.0345333
+1.563 -0.0354296
+1.5635 -0.0361138
+1.564 -0.0365846
+1.5645 -0.0368427
+1.565 -0.0368893
+1.5655 -0.0367274
+1.566 -0.0363606
+1.5665 -0.035794
+1.567 -0.0350334
+1.5675 -0.034086
+1.568 -0.0329599
+1.5685 -0.0316634
+1.569 -0.0302072
+1.5695 -0.028601
+1.57 -0.026856
+1.5705 -0.0249845
+1.571 -0.0229988
+1.5715 -0.0209114
+1.572 -0.0187353
+1.5725 -0.0164848
+1.573 -0.0141734
+1.5735 -0.0118144
+1.574 -0.00942313
+1.5745 -0.00701253
+1.575 -0.00459626
+1.5755 -0.00218904
+1.576 0.000195897
+1.5765 0.00254635
+1.577 0.00484833
+1.5775 0.00709001
+1.578 0.00925935
+1.5785 0.011346
+1.579 0.0133383
+1.5795 0.0152267
+1.58 0.0170024
+1.5805 0.0186564
+1.581 0.0201811
+1.5815 0.0215704
+1.582 0.0228178
+1.5825 0.0239184
+1.583 0.0248682
+1.5835 0.0256642
+1.584 0.0263037
+1.5845 0.0267857
+1.585 0.0271096
+1.5855 0.0272758
+1.586 0.0272858
+1.5865 0.0271417
+1.587 0.0268466
+1.5875 0.0264044
+1.588 0.0258195
+1.5885 0.0250978
+1.589 0.0242449
+1.5895 0.0232678
+1.59 0.0221735
+1.5905 0.0209704
+1.591 0.0196666
+1.5915 0.0182707
+1.592 0.0167925
+1.5925 0.0152414
+1.593 0.0136266
+1.5935 0.0119591
+1.594 0.0102487
+1.5945 0.00850564
+1.595 0.00673997
+1.5955 0.00496288
+1.596 0.00318388
+1.5965 0.00141286
+1.597 -0.000339552
+1.5975 -0.00206392
+1.598 -0.00375159
+1.5985 -0.00539271
+1.599 -0.00697904
+1.5995 -0.00850226
+1.6 -0.0099553
+1.6005 -0.0113302
+1.601 -0.0126208
+1.6015 -0.0138211
+1.602 -0.0149253
+1.6025 -0.0159286
+1.603 -0.0168274
+1.6035 -0.0176176
+1.604 -0.0182966
+1.6045 -0.0188622
+1.605 -0.0193128
+1.6055 -0.0196477
+1.606 -0.0198667
+1.6065 -0.0199703
+1.607 -0.0199596
+1.6075 -0.0198365
+1.608 -0.0196032
+1.6085 -0.0192629
+1.609 -0.018819
+1.6095 -0.0182756
+1.61 -0.0176373
+1.6105 -0.0169092
+1.611 -0.0160966
+1.6115 -0.0152053
+1.612 -0.0142421
+1.6125 -0.0132129
+1.613 -0.0121247
+1.6135 -0.0109847
+1.614 -0.00980029
+1.6145 -0.0085782
+1.615 -0.00732657
+1.6155 -0.00605269
+1.616 -0.00476383
+1.6165 -0.00346804
+1.617 -0.00217263
+1.6175 -0.000884652
+1.618 0.000388846
+1.6185 0.00164037
+1.619 0.00286331
+1.6195 0.00405167
+1.62 0.00519866
+1.6205 0.00629867
+1.621 0.0073464
+1.6215 0.00833631
+1.622 0.00926381
+1.6225 0.0101248
+1.623 0.0109155
+1.6235 0.0116322
+1.624 0.0122721
+1.6245 0.012833
+1.625 0.0133127
+1.6255 0.0137097
+1.626 0.0140233
+1.6265 0.0142527
+1.627 0.0143982
+1.6275 0.0144601
+1.628 0.0144394
+1.6285 0.0143375
+1.629 0.0141563
+1.6295 0.0138979
+1.63 0.0135651
+1.6305 0.013161
+1.631 0.0126887
+1.6315 0.0121524
+1.632 0.0115558
+1.6325 0.0109032
+1.633 0.0101994
+1.6335 0.00944909
+1.634 0.00865719
+1.6345 0.00782868
+1.635 0.00696918
+1.6355 0.00608386
+1.636 0.00517796
+1.6365 0.00425738
+1.637 0.00332721
+1.6375 0.00239276
+1.638 0.00145975
+1.6385 0.000533364
+1.639 -0.000381646
+1.6395 -0.00127982
+1.64 -0.00215651
+1.6405 -0.00300703
+1.641 -0.00382731
+1.6415 -0.00461278
+1.642 -0.00535969
+1.6425 -0.00606459
+1.643 -0.00672387
+1.6435 -0.00733459
+1.644 -0.00789433
+1.6445 -0.00840043
+1.645 -0.008851
+1.6455 -0.00924433
+1.646 -0.00957927
+1.6465 -0.00985468
+1.647 -0.01007
+1.6475 -0.010225
+1.648 -0.0103198
+1.6485 -0.0103547
+1.649 -0.0103306
+1.6495 -0.0102486
+1.65 -0.01011
+1.6505 -0.00991643
+1.651 -0.00967006
+1.6515 -0.00937304
+1.652 -0.00902787
+1.6525 -0.0086372
+1.653 -0.00820419
+1.6535 -0.00773181
+1.654 -0.0072233
+1.6545 -0.00668234
+1.655 -0.00611246
+1.6555 -0.00551714
+1.656 -0.00490045
+1.6565 -0.0042661
+1.657 -0.00361798
+1.6575 -0.00295985
+1.658 -0.00229592
+1.6585 -0.00162979
+1.659 -0.000965188
+1.6595 -0.00030613
+1.66 0.000343815
+1.6605 0.000981375
+1.661 0.00160282
+1.6615 0.00220503
+1.662 0.00278484
+1.6625 0.00333958
+1.663 0.00386622
+1.6635 0.00436236
+1.664 0.00482578
+1.6645 0.00525422
+1.665 0.00564587
+1.6655 0.00599927
+1.666 0.00631287
+1.6665 0.00658563
+1.667 0.0068167
+1.6675 0.00700537
+1.668 0.00715136
+1.6685 0.00725453
+1.669 0.007315
+1.6695 0.00733311
+1.67 0.00730949
+1.6705 0.00724495
+1.671 0.00714054
+1.6715 0.00699752
+1.672 0.0068173
+1.6725 0.00660161
+1.673 0.0063522
+1.6735 0.00607104
+1.674 0.00576021
+1.6745 0.0054221
+1.675 0.00505899
+1.6755 0.00467327
+1.676 0.00426768
+1.6765 0.0038448
+1.677 0.00340716
+1.6775 0.0029577
+1.678 0.00249906
+1.6785 0.00203391
+1.679 0.00156519
+1.6795 0.00109555
+1.68 0.000627586
+1.6805 0.000163868
+1.681 -0.000292861
+1.6815 -0.000740179
+1.682 -0.00117589
+1.6825 -0.0015975
+1.683 -0.00200295
+1.6835 -0.00239029
+1.684 -0.00275748
+1.6845 -0.00310282
+1.685 -0.00342479
+1.6855 -0.003722
+1.686 -0.00399306
+1.6865 -0.00423691
+1.687 -0.00445273
+1.6875 -0.00463965
+1.688 -0.00479717
+1.6885 -0.00492489
+1.689 -0.00502256
+1.6895 -0.00509018
+1.69 -0.00512787
+1.6905 -0.00513592
+1.691 -0.00511479
+1.6915 -0.00506511
+1.692 -0.00498762
+1.6925 -0.00488328
+1.693 -0.00475312
+1.6935 -0.00459828
+1.694 -0.00442015
+1.6945 -0.00422009
+1.695 -0.00399955
+1.6955 -0.00376024
+1.696 -0.00350382
+1.6965 -0.00323199
+1.697 -0.00294652
+1.6975 -0.00264937
+1.698 -0.00234237
+1.6985 -0.00202738
+1.699 -0.00170647
+1.6995 -0.00138144
+1.7 -0.00105416
+1.7005 -0.000726663
+1.701 -0.000400775
+1.7015 -7.81849e-05
+1.702 0.000239175
+1.7025 0.000549661
+1.703 0.000851603
+1.7035 0.00114356
+1.704 0.0014239
+1.7045 0.00169129
+1.705 0.0019445
+1.7055 0.00218224
+1.706 0.00240346
+1.7065 0.00260728
+1.707 0.00279274
+1.7075 0.00295915
+1.708 0.0031059
+1.7085 0.00323254
+1.709 0.00333865
+1.7095 0.00342401
+1.71 0.00348852
+1.7105 0.00353213
+1.711 0.00355501
+1.7115 0.00355737
+1.712 0.00353956
+1.7125 0.00350205
+1.713 0.00344537
+1.7135 0.00337022
+1.714 0.00327733
+1.7145 0.00316754
+1.715 0.00304176
+1.7155 0.00290102
+1.716 0.00274636
+1.7165 0.00257887
+1.717 0.0023998
+1.7175 0.00221035
+1.718 0.0020117
+1.7185 0.00180524
+1.719 0.00159225
+1.7195 0.00137404
+1.72 0.0011519
+1.7205 0.000927272
+1.721 0.000701385
+1.7215 0.00047552
+1.722 0.000251046
+1.7225 2.91893e-05
+1.723 -0.000188927
+1.7235 -0.000402025
+1.724 -0.000609027
+1.7245 -0.000808851
+1.725 -0.00100057
+1.7255 -0.00118314
+1.726 -0.00135574
+1.7265 -0.00151759
+1.727 -0.00166791
+1.7275 -0.00180607
+1.728 -0.00193156
+1.7285 -0.00204382
+1.729 -0.0021425
+1.7295 -0.00222728
+1.73 -0.0022979
+1.7305 -0.00235424
+1.731 -0.00239625
+1.7315 -0.00242393
+1.732 -0.00243738
+1.7325 -0.0024368
+1.733 -0.00242243
+1.7335 -0.00239462
+1.734 -0.00235376
+1.7345 -0.0023003
+1.735 -0.00223481
+1.7355 -0.00215786
+1.736 -0.0020701
+1.7365 -0.0019722
+1.737 -0.00186495
+1.7375 -0.00174909
+1.738 -0.00162542
+1.7385 -0.00149484
+1.739 -0.00135819
+1.7395 -0.00121632
+1.74 -0.00107018
+1.7405 -0.000920672
+1.741 -0.000768657
+1.7415 -0.000615112
+1.742 -0.000460919
+1.7425 -0.000306936
+1.743 -0.000154016
+1.7435 -3.06876e-06
+1.744 0.000145101
+1.7445 0.000289763
+1.745 0.000430088
+1.7455 0.000565389
+1.746 0.000695016
+1.7465 0.000818285
+1.747 0.000934631
+1.7475 0.00104354
+1.748 0.00114455
+1.7485 0.00123719
+1.749 0.00132109
+1.7495 0.00139598
+1.75 0.00146156
+1.7505 0.00151765
+1.751 0.0015641
+1.7515 0.00160082
+1.752 0.0016278
+1.7525 0.00164506
+1.753 0.00165268
+1.7535 0.00165079
+1.754 0.0016396
+1.7545 0.00161932
+1.755 0.00159025
+1.7555 0.00155272
+1.756 0.00150709
+1.7565 0.00145379
+1.757 0.00139325
+1.7575 0.00132594
+1.758 0.00125239
+1.7585 0.00117314
+1.759 0.00108873
+1.7595 0.000999717
+1.76 0.000906734
+1.7605 0.000810364
+1.761 0.000711199
+1.7615 0.000609903
+1.762 0.000507054
+1.7625 0.000403251
+1.763 0.000299144
+1.7635 0.000195321
+1.764 9.23221e-05
+1.7645 -9.23019e-06
+1.765 -0.000108808
+1.7655 -0.000205873
+1.766 -0.000299961
+1.7665 -0.000390545
+1.767 -0.000477198
+1.7675 -0.000559518
+1.768 -0.000637087
+1.7685 -0.000709563
+1.769 -0.000776661
+1.7695 -0.000838068
+1.77 -0.000893556
+1.7705 -0.000942918
+1.771 -0.000986009
+1.7715 -0.00102268
+1.772 -0.00105286
+1.7725 -0.0010765
+1.773 -0.00109358
+1.7735 -0.00110414
+1.774 -0.00110824
+1.7745 -0.00110598
+1.775 -0.00109749
+1.7755 -0.00108295
+1.776 -0.00106255
+1.7765 -0.00103652
+1.777 -0.00100512
+1.7775 -0.00096862
+1.778 -0.000927342
+1.7785 -0.0008816
+1.779 -0.000831732
+1.7795 -0.000778123
+1.78 -0.000721143
+1.7805 -0.000661158
+1.781 -0.000598597
+1.7815 -0.000533853
+1.782 -0.000467336
+1.7825 -0.000399443
+1.783 -0.000330622
+1.7835 -0.000261255
+1.784 -0.000191737
+1.7845 -0.000122496
+1.785 -5.39127e-05
+1.7855 1.36643e-05
+1.786 7.98362e-05
+1.7865 0.000144268
+1.787 0.000206621
+1.7875 0.000266607
+1.788 0.000323899
+1.7885 0.000378238
+1.789 0.000429382
+1.7895 0.000477082
+1.79 0.000521141
+1.7905 0.000561396
+1.791 0.000597673
+1.7915 0.00062985
+1.792 0.000657832
+1.7925 0.000681526
+1.793 0.000700895
+1.7935 0.000715909
+1.794 0.000726571
+1.7945 0.0007329
+1.795 0.000734951
+1.7955 0.000732793
+1.796 0.000726522
+1.7965 0.000716255
+1.797 0.000702125
+1.7975 0.000684297
+1.798 0.000662939
+1.7985 0.000638244
+1.799 0.000610412
+1.7995 0.000579676
+1.8 0.000546258
+1.8005 0.000510397
+1.801 0.000472359
+1.8015 0.0004324
+1.802 0.000390768
+1.8025 0.000347756
+1.803 0.000303625
+1.8035 0.00025864
+1.804 0.000213091
+1.8045 0.000167245
+1.805 0.000121358
+1.8055 7.56883e-05
+1.806 3.05086e-05
+1.8065 -1.39384e-05
+1.807 -5.74324e-05
+1.8075 -9.97231e-05
+1.808 -0.000140603
+1.8085 -0.000179876
+1.809 -0.000217334
+1.8095 -0.000252807
+1.81 -0.000286138
+1.8105 -0.000317184
+1.811 -0.000345801
+1.8115 -0.000371879
+1.812 -0.000395332
+1.8125 -0.000416065
+1.813 -0.000434021
+1.8135 -0.000449157
+1.814 -0.000461434
+1.8145 -0.000470848
+1.815 -0.000477401
+1.8155 -0.000481113
+1.816 -0.000482019
+1.8165 -0.000480173
+1.817 -0.000475638
+1.8175 -0.000468496
+1.818 -0.000458841
+1.8185 -0.000446775
+1.819 -0.000432421
+1.8195 -0.000415904
+1.82 -0.000397357
+1.8205 -0.000376935
+1.821 -0.000354791
+1.8215 -0.000331082
+1.822 -0.00030597
+1.8225 -0.000279638
+1.823 -0.000252254
+1.8235 -0.000223991
+1.824 -0.00019504
+1.8245 -0.00016557
+1.825 -0.000135756
+1.8255 -0.000105786
+1.826 -7.58303e-05
+1.8265 -4.60475e-05
+1.827 -1.66184e-05
+1.8275 1.23028e-05
+1.828 4.05593e-05
+1.8285 6.8015e-05
+1.829 9.45162e-05
+1.8295 0.000119937
+1.83 0.000144161
+1.8305 0.000167064
+1.831 0.000188545
+1.8315 0.000208521
+1.832 0.000226898
+1.8325 0.000243609
+1.833 0.000258591
+1.8335 0.0002718
+1.834 0.000283191
+1.8345 0.000292739
+1.835 0.00030043
+1.8355 0.000306253
+1.836 0.000310218
+1.8365 0.000312341
+1.837 0.000312645
+1.8375 0.000311168
+1.838 0.000307953
+1.8385 0.000303058
+1.839 0.000296543
+1.8395 0.00028848
+1.84 0.000278943
+1.8405 0.000268024
+1.841 0.000255809
+1.8415 0.000242393
+1.842 0.000227882
+1.8425 0.00021238
+1.843 0.000195991
+1.8435 0.000178834
+1.844 0.000161019
+1.8445 0.000142662
+1.845 0.000123874
+1.8455 0.000104781
+1.846 8.54898e-05
+1.8465 6.61132e-05
+1.847 4.67707e-05
+1.8475 2.75697e-05
+1.848 8.60894e-06
+1.8485 -9.9992e-06
+1.849 -2.816e-05
+1.8495 -4.57777e-05
+1.85 -6.27703e-05
+1.8505 -7.90457e-05
+1.851 -9.45297e-05
+1.8515 -0.000109154
+1.852 -0.000122847
+1.8525 -0.000135552
+1.853 -0.000147222
+1.8535 -0.000157807
+1.854 -0.000167273
+1.8545 -0.00017559
+1.855 -0.000182733
+1.8555 -0.000188686
+1.856 -0.000193441
+1.8565 -0.000196997
+1.857 -0.000199357
+1.8575 -0.000200535
+1.858 -0.000200548
+1.8585 -0.000199421
+1.859 -0.000197186
+1.8595 -0.000193877
+1.86 -0.000189537
+1.8605 -0.000184212
+1.861 -0.000177954
+1.8615 -0.000170816
+1.862 -0.000162861
+1.8625 -0.000154151
+1.863 -0.000144748
+1.8635 -0.000134726
+1.864 -0.000124152
+1.8645 -0.000113095
+1.865 -0.000101635
+1.8655 -8.98416e-05
+1.866 -7.77878e-05
+1.8665 -6.55524e-05
+1.867 -5.32067e-05
+1.8675 -4.08257e-05
+1.868 -2.8471e-05
+1.8685 -1.62269e-05
+1.869 -4.15112e-06
+1.8695 7.69111e-06
+1.87 1.92326e-05
+1.8705 3.04165e-05
+1.871 4.11889e-05
+1.8715 5.14929e-05
+1.872 6.12822e-05
+1.8725 7.051e-05
+1.873 7.91416e-05
+1.8735 8.71353e-05
+1.874 9.44609e-05
+1.8745 0.000101092
+1.875 0.000107004
+1.8755 0.00011218
+1.876 0.000116607
+1.8765 0.000120274
+1.877 0.000123178
+1.8775 0.000125318
+1.878 0.000126699
+1.8785 0.00012733
+1.879 0.000127223
+1.8795 0.000126395
+1.88 0.000124867
+1.8805 0.000122661
+1.881 0.000119806
+1.8815 0.000116332
+1.882 0.000112273
+1.8825 0.000107661
+1.883 0.000102541
+1.8835 9.69478e-05
+1.884 9.0926e-05
+1.8845 8.45172e-05
+1.885 7.77691e-05
+1.8855 7.07265e-05
+1.886 6.34342e-05
+1.8865 5.59424e-05
+1.887 4.82981e-05
+1.8875 4.05437e-05
+1.888 3.27304e-05
+1.8885 2.49024e-05
+1.889 1.71032e-05
+1.8895 9.37968e-06
+1.89 1.77265e-06
+1.8905 -5.67709e-06
+1.891 -1.2932e-05
+1.8915 -1.9952e-05
+1.892 -2.67025e-05
+1.8925 -3.31548e-05
+1.893 -3.92749e-05
+1.8935 -4.50365e-05
+1.894 -5.04156e-05
+1.8945 -5.53879e-05
+1.895 -5.99352e-05
+1.8955 -6.40408e-05
+1.896 -6.76919e-05
+1.8965 -7.08762e-05
+1.897 -7.35861e-05
+1.8975 -7.58183e-05
+1.898 -7.75691e-05
+1.8985 -7.88397e-05
+1.899 -7.96335e-05
+1.8995 -7.99564e-05
+1.9 -7.98172e-05
+1.9005 -7.92267e-05
+1.901 -7.81986e-05
+1.9015 -7.67485e-05
+1.902 -7.4894e-05
+1.9025 -7.26541e-05
+1.903 -7.00511e-05
+1.9035 -6.71076e-05
+1.904 -6.38472e-05
+1.9045 -6.02969e-05
+1.905 -5.64828e-05
+1.9055 -5.24317e-05
+1.906 -4.81737e-05
+1.9065 -4.37376e-05
+1.907 -3.91513e-05
+1.9075 -3.44439e-05
+1.908 -2.96471e-05
+1.9085 -2.47891e-05
+1.909 -1.98981e-05
+1.9095 -1.50047e-05
+1.91 -1.01359e-05
+1.9105 -5.31799e-06
+1.911 -5.79145e-07
+1.9115 4.05536e-06
+1.912 8.56329e-06
+1.9125 1.29217e-05
+1.913 1.71074e-05
+1.9135 2.11013e-05
+1.914 2.48856e-05
+1.9145 2.8442e-05
+1.915 3.1756e-05
+1.9155 3.48149e-05
+1.916 3.76052e-05
+1.9165 4.01187e-05
+1.917 4.23474e-05
+1.9175 4.4284e-05
+1.918 4.59245e-05
+1.9185 4.72662e-05
+1.919 4.83086e-05
+1.9195 4.90519e-05
+1.92 4.94991e-05
+1.9205 4.96542e-05
+1.921 4.95229e-05
+1.9215 4.91127e-05
+1.922 4.8432e-05
+1.9225 4.74911e-05
+1.923 4.63011e-05
+1.9235 4.48746e-05
+1.924 4.32248e-05
+1.9245 4.13667e-05
+1.925 3.93155e-05
+1.9255 3.70868e-05
+1.926 3.46986e-05
+1.9265 3.21671e-05
+1.927 2.95098e-05
+1.9275 2.67458e-05
+1.928 2.38928e-05
+1.9285 2.09685e-05
+1.929 1.79924e-05
+1.9295 1.49822e-05
+1.93 1.19563e-05
+1.9305 8.93009e-06
+1.931 5.92437e-06
+1.9315 2.95345e-06
+1.932 3.35029e-08
+1.9325 -2.8188e-06
+1.933 -5.58933e-06
+1.9335 -8.26467e-06
+1.934 -1.08307e-05
+1.9345 -1.32758e-05
+1.935 -1.55883e-05
+1.9355 -1.77594e-05
+1.936 -1.97788e-05
+1.9365 -2.16387e-05
+1.937 -2.33327e-05
+1.9375 -2.48541e-05
+1.938 -2.61987e-05
+1.9385 -2.7363e-05
+1.939 -2.83441e-05
+1.9395 -2.9141e-05
+1.94 -2.97534e-05
+1.9405 -3.01817e-05
+1.941 -3.04283e-05
+1.9415 -3.04957e-05
+1.942 -3.03877e-05
+1.9425 -3.0109e-05
+1.943 -2.96653e-05
+1.9435 -2.90626e-05
+1.944 -2.83084e-05
+1.9445 -2.74107e-05
+1.945 -2.63771e-05
+1.9455 -2.52179e-05
+1.946 -2.39418e-05
+1.9465 -2.2559e-05
+1.947 -2.10797e-05
+1.9475 -1.95152e-05
+1.948 -1.7876e-05
+1.9485 -1.61729e-05
+1.949 -1.44179e-05
+1.9495 -1.26222e-05
+1.95 -1.07959e-05
+1.9505 -8.95136e-06
+1.951 -7.09906e-06
+1.9515 -5.24942e-06
+1.952 -3.4137e-06
+1.9525 -1.60169e-06
+1.953 1.76813e-07
+1.9535 1.91279e-06
+1.954 3.59662e-06
+1.9545 5.21993e-06
+1.955 6.77584e-06
+1.9555 8.2561e-06
+1.956 9.65433e-06
+1.9565 1.09648e-05
+1.957 1.21814e-05
+1.9575 1.32999e-05
+1.958 1.4316e-05
+1.9585 1.52266e-05
+1.959 1.60287e-05
+1.9595 1.67201e-05
+1.96 1.73001e-05
+1.9605 1.77676e-05
+1.961 1.81226e-05
+1.9615 1.83659e-05
+1.962 1.84986e-05
+1.9625 1.85226e-05
+1.963 1.84404e-05
+1.9635 1.82549e-05
+1.964 1.79698e-05
+1.9645 1.7589e-05
+1.965 1.71167e-05
+1.9655 1.65582e-05
+1.966 1.59186e-05
+1.9665 1.52032e-05
+1.967 1.44184e-05
+1.9675 1.357e-05
+1.968 1.26642e-05
+1.9685 1.17081e-05
+1.969 1.07082e-05
+1.9695 9.67102e-06
+1.97 8.60324e-06
+1.9705 7.51217e-06
+1.971 6.40439e-06
+1.9715 5.2864e-06
+1.972 4.1653e-06
+1.9725 3.04734e-06
+1.973 1.93862e-06
+1.9735 8.45705e-07
+1.974 -2.25546e-07
+1.9745 -1.26996e-06
+1.975 -2.28218e-06
+1.9755 -3.25681e-06
+1.976 -4.18937e-06
+1.9765 -5.07572e-06
+1.977 -5.91155e-06
+1.9775 -6.69348e-06
+1.978 -7.41846e-06
+1.9785 -8.0833e-06
+1.979 -8.68609e-06
+1.9795 -9.22484e-06
+1.98 -9.69779e-06
+1.9805 -1.01039e-05
+1.981 -1.04426e-05
+1.9815 -1.07135e-05
+1.982 -1.09166e-05
+1.9825 -1.10524e-05
+1.983 -1.11219e-05
+1.9835 -1.11262e-05
+1.984 -1.10668e-05
+1.9845 -1.09457e-05
+1.985 -1.07651e-05
+1.9855 -1.05275e-05
+1.986 -1.02355e-05
+1.9865 -9.89205e-06
+1.987 -9.5006e-06
+1.9875 -9.06445e-06
+1.988 -8.58707e-06
+1.9885 -8.07249e-06
+1.989 -7.5243e-06
+1.9895 -6.94641e-06
+1.99 -6.34309e-06
+1.9905 -5.7183e-06
+1.991 -5.07601e-06
+1.9915 -4.42057e-06
+1.992 -3.75593e-06
+1.9925 -3.08625e-06
+1.993 -2.41497e-06
+1.9935 -1.74674e-06
+1.994 -1.08481e-06
+1.9945 -4.32789e-07
+1.995 2.0556e-07
+1.9955 8.27053e-07
+1.996 1.42867e-06
+1.9965 2.0072e-06
+1.997 2.56005e-06
+1.9975 3.08454e-06
+1.998 3.57871e-06
+1.9985 4.04017e-06
+1.999 4.46717e-06
+1.9995 4.85819e-06
+2 5.21174e-06
+&
index fd5b51bbb2d0cc2ea2684d9e2b4b57be48c8d928..87c9ddbfc7f5e0b22f2d166eb145c439013b3dec 100644 (file)
@@ -1048,6 +1048,58 @@ rotation, torques $\ve{\tau}_{\!n}$ are calculated for each slab using the
 local rotation axis of the slab and the Gaussian-weighted positions.
 
 
+\section{\normindex{Electric fields}}
+A pulsed and oscillating electric field can be applied according to:
+\begin{equation}
+E(t) = E_0 \exp\left[-\frac{(t-t_0)^2}{2\sigma^2}\right]\cos\left[\omega (t-t_0)\right]
+\label{eq_efield}
+\end{equation}
+where $E_0$ is the field strength, the angular frequency \mbox{$\omega = 2\pi c/\lambda$}, $t_0$ is
+the time at of the peak in the field strength and $\sigma$ is the with
+of the pulse. Special cases occur when $\sigma$ = 0 (non-pulsed field)
+and for $\omega$ is 0 (static field).
+
+This simulated \normindex{laser}-pulse was applied to
+simulations of melting ice~\cite{Caleman2008a}. A pulsed electric field may
+look ike Fig.~\ref{fig:field}. In the supporting
+information of that paper the impact of an applied electric field on a
+system under periodic boundary conditions is analyzed. It is described
+that the effective electric field under PBC is larger than the applied
+field, by a factor depending on the size of the box and the dielectric
+properties of molecules in the box. For a system with static dielectric
+properties this factor can be corrected for. But for a system where
+the dielectric varies over time, for example a membrane protein with
+a pore that opens and closes during the simulatippn, this way of applying
+an electric field is not useful. In such cases one can use the computational
+electrophysiology protocol described in the next section (\secref{compel}).
+\begin{figure}[ht]
+\centerline{\includegraphics[width=8cm]{plots/field}}
+\caption {A simulated laser pulse in GROMACS.}
+\label{fig:field}
+\end{figure}
+
+Electric fields are applied when the following options are specified
+in the {\tt grompp.mdp} file. You specify, in order, $E_0$, $\omega$,
+$t_0$ and $\sigma$:
+\begin{verbatim}
+ElectricField-x = 0.04 0       0     0
+\end{verbatim}
+yields a static field with $E_0$ = 0.04 V/nm in the X-direction. In contrast,
+\begin{verbatim}
+ElectricField-x = 2.0  150     5     0
+\end{verbatim}
+yields an oscillating electric field with $E_0$ = 2 V/nm, $\omega$ = 150/ps and
+$t_0$ = 5 ps. Finally 
+\begin{verbatim}
+ElectricField-x = 2.0  150     5     1
+\end{verbatim}
+yields an pulsed-oscillating electric field with $E_0$ = 2 V/nm, $\omega$ = 150/ps and
+$t_0$ = 5 ps and $\sigma$ = 1 ps. Read more in ref.~\cite{Caleman2008a}.
+Note that the input file format is changed from the undocumented older
+version. A figure like Fig.~\ref{fig:field} may be produced by passing
+the {\tt -field} option to {\tt gmx mdrun}.
+
+
 \section{\normindex{Computational Electrophysiology}}
 \label{sec:compel}
 
index b92d81ba1b1a7b307e45e04441b80fe13bf1c32f..4148300c143b6e38f83e6980c74ebb0a5551b79a 100644 (file)
@@ -141,6 +141,18 @@ linked help for the new commands for a full description.
 This section lists only major changes; minor changes like additional/removed
 options or bug fixes are not typically included.
 
+Version 2017
+^^^^^^^^^^^^
+
+gmx trajectory
+..............
+
+**new**
+
+:ref:`gmx trajectory` has been introduced as a selection-enabled version of
+:ref:`gmx traj`.  It supports output of coordinates, velocities, and/or forces
+for positions calculated for selections.
+
 Version 2016
 ^^^^^^^^^^^^
 
index 6720381b35328b8e05ab8962a5897f6547aab4cf..271abfd1db4a3e9434232ed35d4d37b8e96b1b60 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8.8)
+cmake_minimum_required(VERSION 3.4.3)
 
 project(template CXX)
 
index 11829495889c933dc8b9fa05e0f3af8ff8791f41..f120b01add4bf0da3db4321cc72aeafd86a88513 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2009,2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+# Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -55,15 +55,7 @@ if (BUILD_TESTING)
         add_subdirectory(external/gmock-1.7.0)
     endif()
     include(testutils/TestMacros.cmake)
-    if (GMX_BUILD_UNITTESTS)
-        add_subdirectory(testutils)
-    else()
-        add_custom_target(unittests-notice
-            ${CMAKE_COMMAND} -E echo "NOTE: Unit tests have not been run. You need to set GMX_BUILD_UNITTESTS=ON if you want to build and run them."
-            DEPENDS run-ctest
-            COMMENT "Unit tests disabled" VERBATIM)
-        add_dependencies(check unittests-notice)
-    endif()
+    add_subdirectory(testutils)
 endif()
 
 add_subdirectory(gromacs)
index c7bd5fb3dab936c13a5ce09708c54fcb0572acc3..587490c59a166dc114fe1823c440816af237d819 100644 (file)
@@ -74,9 +74,6 @@
 /** Define if we are building for Cygwin */
 #cmakedefine01 GMX_CYGWIN
 
-/* GCC bug in AVX maskload/maskstore arguments - worked around internally */
-#cmakedefine01 GMX_SIMD_X86_AVX_GCC_MASKLOAD_BUG
-
 /* SSE2 was selected for SIMD instruction set level */
 #cmakedefine01 GMX_SIMD_X86_SSE2
 
 /* Define if we have feenableexcept */
 #cmakedefine01 HAVE_FEENABLEEXCEPT
 
-/* Define if we have zlib */
-#cmakedefine01 HAVE_ZLIB
-
 /*! \endcond */
 
 #endif
index 35acd0a7e6717c378ac0b3406624443181b51c58..fa220cf29a26299d2be310491c336a13ec0f1e1e 100644 (file)
@@ -65,6 +65,11 @@ find_package(Threads)
 set(PTHREADS_LIBRARIES)
 if (CMAKE_USE_PTHREADS_INIT)
     set(PTHREADS_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
+    list(APPEND GMOCK_COMPILE_DEFINITIONS "GTEST_HAS_PTHREAD=1")
+    set(GTEST_IS_THREADSAFE 1)
+else()
+    list(APPEND GMOCK_COMPILE_DEFINITIONS "GTEST_HAS_PTHREAD=0")
+    set(GTEST_IS_THREADSAFE 0)
 endif()
 
 # Skip variadic implementation of matchers if using GCC < 4.7 due to
@@ -101,3 +106,4 @@ set(GMOCK_INCLUDE_DIRS ${GMOCK_INCLUDE_DIRS} PARENT_SCOPE)
 set(GTEST_INCLUDE_DIRS ${GTEST_INCLUDE_DIRS} PARENT_SCOPE)
 set(GMOCK_COMPILE_DEFINITIONS ${GMOCK_COMPILE_DEFINITIONS} PARENT_SCOPE)
 set(GMOCK_COMPILE_FLAGS "${GMOCK_COMPILE_FLAGS}" PARENT_SCOPE)
+set(GTEST_IS_THREADSAFE "${GTEST_IS_THREADSAFE}" PARENT_SCOPE)
index 38af58fe2426c630e14eed18fee47f2ff28a7109..5e9c472806b05ce0f50f26b3a44f6e0e39527402 100644 (file)
@@ -2,7 +2,7 @@
    This source code file is part of thread_mpi.
    Written by Sander Pronk, Erik Lindahl, and possibly others.
 
-   Copyright (c) 2009, Sander Pronk, Erik Lindahl.
+   Copyright (c) 2009,2016, Sander Pronk, Erik Lindahl.
    All rights reserved.
 
    Redistribution and use in source and binary forms, with or without
@@ -884,7 +884,7 @@ int tMPI_Type_commit(tMPI_Datatype *datatype);
     \param[in]  comm        The shared communicator.
     \return  TMPI_SUCCESS on success, TMPI_FAILURE on failure.  */
 TMPI_EXPORT
-int tMPI_Send(void* buf, int count, tMPI_Datatype datatype, int dest,
+int tMPI_Send(const void* buf, int count, tMPI_Datatype datatype, int dest,
               int tag, tMPI_Comm comm);
 
 /** Receive message; blocks until buf is filled.
@@ -919,7 +919,7 @@ int tMPI_Recv(void* buf, int count, tMPI_Datatype datatype, int source,
     \param[out] status      The received message status.
     \return  TMPI_SUCCESS on success, TMPI_FAILURE on failure.  */
 TMPI_EXPORT
-int tMPI_Sendrecv(void *sendbuf, int sendcount, tMPI_Datatype sendtype,
+int tMPI_Sendrecv(const void *sendbuf, int sendcount, tMPI_Datatype sendtype,
                   int dest, int sendtag, void *recvbuf, int recvcount,
                   tMPI_Datatype recvtype, int source, int recvtag,
                   tMPI_Comm comm, tMPI_Status *status);
@@ -945,7 +945,7 @@ int tMPI_Sendrecv(void *sendbuf, int sendcount, tMPI_Datatype sendtype,
                             tMPI_Test, etc.
     \return  TMPI_SUCCESS on success, TMPI_FAILURE on failure.  */
 TMPI_EXPORT
-int tMPI_Isend(void* buf, int count, tMPI_Datatype datatype, int dest,
+int tMPI_Isend(const void* buf, int count, tMPI_Datatype datatype, int dest,
                int tag, tMPI_Comm comm, tMPI_Request *request);
 
 /** Initiate receiving a message.
@@ -1164,7 +1164,7 @@ int tMPI_Bcast(void* buffer, int count, tMPI_Datatype datatype, int root,
 
     \return  TMPI_SUCCESS on success, TMPI_FAILURE on failure.  */
 TMPI_EXPORT
-int tMPI_Gather(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
+int tMPI_Gather(const void* sendbuf, int sendcount, tMPI_Datatype sendtype,
                 void* recvbuf, int recvcount, tMPI_Datatype recvtype, int root,
                 tMPI_Comm comm);
 
@@ -1189,7 +1189,7 @@ int tMPI_Gather(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
 
     \return  TMPI_SUCCESS on success, TMPI_FAILURE on failure.  */
 TMPI_EXPORT
-int tMPI_Gatherv(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
+int tMPI_Gatherv(const void* sendbuf, int sendcount, tMPI_Datatype sendtype,
                  void* recvbuf, int *recvcounts, int *displs,
                  tMPI_Datatype recvtype, int root, tMPI_Comm comm);
 
@@ -1212,7 +1212,7 @@ int tMPI_Gatherv(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
 
     \return  TMPI_SUCCESS on success, TMPI_FAILURE on failure.  */
 TMPI_EXPORT
-int tMPI_Scatter(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
+int tMPI_Scatter(const void* sendbuf, int sendcount, tMPI_Datatype sendtype,
                  void* recvbuf, int recvcount, tMPI_Datatype recvtype, int root,
                  tMPI_Comm comm);
 
@@ -1237,7 +1237,7 @@ int tMPI_Scatter(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
 
     \return  TMPI_SUCCESS on success, TMPI_FAILURE on failure.  */
 TMPI_EXPORT
-int tMPI_Scatterv(void* sendbuf, int *sendcounts, int *displs,
+int tMPI_Scatterv(const void* sendbuf, int *sendcounts, int *displs,
                   tMPI_Datatype sendtype, void* recvbuf, int recvcount,
                   tMPI_Datatype recvtype, int root, tMPI_Comm comm);
 
index 54e91bf69b64430ad336ed53cd82d0eba9b529c8..ca928a197aa1c91665616cab49f36ce1e2778255 100644 (file)
@@ -2,7 +2,7 @@
    This source code file is part of thread_mpi.
    Written by Sander Pronk, Erik Lindahl, and possibly others.
 
-   Copyright (c) 2009, Sander Pronk, Erik Lindahl.
+   Copyright (c) 2009,2016, Sander Pronk, Erik Lindahl.
    All rights reserved.
 
    Redistribution and use in source and binary forms, with or without
@@ -58,7 +58,7 @@
 #include "collective.h"
 
 
-int tMPI_Gather(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
+int tMPI_Gather(const void* sendbuf, int sendcount, tMPI_Datatype sendtype,
                 void* recvbuf, int recvcount, tMPI_Datatype recvtype,
                 int root, tMPI_Comm comm)
 {
@@ -96,7 +96,7 @@ int tMPI_Gather(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
             tMPI_Coll_root_xfer(comm, sendtype, recvtype,
                                 sendtype->size*sendcount,
                                 recvtype->size*recvcount,
-                                sendbuf,
+                                (void*)sendbuf,
                                 (char*)recvbuf+myrank*recvcount*recvtype->size,
                                 &ret);
         }
@@ -146,7 +146,7 @@ int tMPI_Gather(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
 
         /* first set up the data just to root. */
         ret = tMPI_Post_multi(cev, myrank, 0, TMPI_GATHER_TAG, sendtype,
-                              sendcount*sendtype->size, sendbuf, 1, synct, root);
+                              sendcount*sendtype->size, (void*)sendbuf, 1, synct, root);
         if (ret != TMPI_SUCCESS)
         {
             return ret;
@@ -165,7 +165,7 @@ int tMPI_Gather(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
 
 
 
-int tMPI_Gatherv(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
+int tMPI_Gatherv(const void* sendbuf, int sendcount, tMPI_Datatype sendtype,
                  void* recvbuf, int *recvcounts, int *displs,
                  tMPI_Datatype recvtype, int root, tMPI_Comm comm)
 {
@@ -203,7 +203,7 @@ int tMPI_Gatherv(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
             tMPI_Coll_root_xfer(comm, sendtype, recvtype,
                                 sendtype->size*sendcount,
                                 recvtype->size*recvcounts[myrank],
-                                sendbuf,
+                                (void*)sendbuf,
                                 (char*)recvbuf+displs[myrank]*recvtype->size,
                                 &ret);
         }
@@ -252,7 +252,7 @@ int tMPI_Gatherv(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
 
         /* first set up the data just to root. */
         ret = tMPI_Post_multi(cev, myrank, 0, TMPI_GATHERV_TAG, sendtype,
-                              sendcount*sendtype->size, sendbuf, 1, synct, root);
+                              sendcount*sendtype->size, (void*)sendbuf, 1, synct, root);
         if (ret != TMPI_SUCCESS)
         {
             return ret;
index 3d0379cac7fc6b328dd2f930ce69ef747d9e473a..d3a2dcad7e91633690595747c0214b6d830471a3 100644 (file)
@@ -2,7 +2,7 @@
    This source code file is part of thread_mpi.
    Written by Sander Pronk, Erik Lindahl, and possibly others.
 
-   Copyright (c) 2009, Sander Pronk, Erik Lindahl.
+   Copyright (c) 2009,2016, Sander Pronk, Erik Lindahl.
    All rights reserved.
 
    Redistribution and use in source and binary forms, with or without
@@ -61,7 +61,7 @@
 
 /* point-to-point communication exported functions */
 
-int tMPI_Send(void* buf, int count, tMPI_Datatype datatype, int dest,
+int tMPI_Send(const void* buf, int count, tMPI_Datatype datatype, int dest,
               int tag, tMPI_Comm comm)
 {
     struct envelope    *sev;
@@ -86,7 +86,7 @@ int tMPI_Send(void* buf, int count, tMPI_Datatype datatype, int dest,
         return tMPI_Error(comm, TMPI_ERR_SEND_DEST);
     }
 
-    sev = tMPI_Post_send(cur, comm, send_dst, buf, count, datatype, tag, FALSE);
+    sev = tMPI_Post_send(cur, comm, send_dst, (void*)buf, count, datatype, tag, FALSE);
     if (sev == NULL)
     {
         return TMPI_ERR_ENVELOPES;
@@ -152,7 +152,7 @@ int tMPI_Recv(void* buf, int count, tMPI_Datatype datatype, int source,
 
 
 
-int tMPI_Sendrecv(void *sendbuf, int sendcount, tMPI_Datatype sendtype,
+int tMPI_Sendrecv(const void *sendbuf, int sendcount, tMPI_Datatype sendtype,
                   int dest, int sendtag, void *recvbuf, int recvcount,
                   tMPI_Datatype recvtype, int source, int recvtag,
                   tMPI_Comm comm, tMPI_Status *status)
@@ -191,7 +191,7 @@ int tMPI_Sendrecv(void *sendbuf, int sendcount, tMPI_Datatype sendtype,
     }
 
     /* we first prepare to send */
-    sev = tMPI_Post_send(cur, comm, send_dst, sendbuf, sendcount,
+    sev = tMPI_Post_send(cur, comm, send_dst, (void*)sendbuf, sendcount,
                          sendtype, sendtag, FALSE);
     if (sev == NULL)
     {
@@ -244,7 +244,7 @@ int tMPI_Sendrecv(void *sendbuf, int sendcount, tMPI_Datatype sendtype,
 
 /* async */
 
-int tMPI_Isend(void* buf, int count, tMPI_Datatype datatype, int dest,
+int tMPI_Isend(const void* buf, int count, tMPI_Datatype datatype, int dest,
                int tag, tMPI_Comm comm, tMPI_Request *request)
 {
     struct tmpi_thread *cur = tMPI_Get_current();
@@ -271,7 +271,7 @@ int tMPI_Isend(void* buf, int count, tMPI_Datatype datatype, int dest,
         tMPI_Return_req(rql, rq);
         return tMPI_Error(comm, TMPI_ERR_SEND_DEST);
     }
-    ev = tMPI_Post_send(cur, comm, send_dst, buf, count, datatype, tag, TRUE);
+    ev = tMPI_Post_send(cur, comm, send_dst, (void*)buf, count, datatype, tag, TRUE);
     if (ev == NULL)
     {
         return TMPI_ERR_ENVELOPES;
index 807f85a3959255e769b1bd306cf59c7dbace76aa..03117a34b977c75529c8fb0216b105ba791e65bf 100644 (file)
@@ -2,7 +2,7 @@
    This source code file is part of thread_mpi.
    Written by Sander Pronk, Erik Lindahl, and possibly others.
 
-   Copyright (c) 2009, Sander Pronk, Erik Lindahl.
+   Copyright (c) 2009,2016, Sander Pronk, Erik Lindahl.
    All rights reserved.
 
    Redistribution and use in source and binary forms, with or without
@@ -59,7 +59,7 @@
 
 
 
-int tMPI_Scatter(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
+int tMPI_Scatter(const void* sendbuf, int sendcount, tMPI_Datatype sendtype,
                  void* recvbuf, int recvcount, tMPI_Datatype recvtype,
                  int root, tMPI_Comm comm)
 {
@@ -195,7 +195,7 @@ int tMPI_Scatter(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
 
 
 
-int tMPI_Scatterv(void* sendbuf, int *sendcounts, int *displs,
+int tMPI_Scatterv(const void* sendbuf, int *sendcounts, int *displs,
                   tMPI_Datatype sendtype, void* recvbuf, int recvcount,
                   tMPI_Datatype recvtype, int root, tMPI_Comm comm)
 {
index 5a7432cd8289df56f68625fa951699dae6e8287c..3cc9f26372180cce69a6e923b4433edaecc6f69e 100644 (file)
@@ -1,11 +1,14 @@
 set(TNG_ROOT_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR})
 file(RELATIVE_PATH TNG_ROOT_BINARY_DIR ${CMAKE_SOURCE_DIR} ${TNG_ROOT_SOURCE_DIR})
+if ("${TNG_ROOT_BINARY_DIR}" MATCHES "^\.\.")
+    set(TNG_ROOT_BINARY_DIR tng)
+endif()
 set(TNG_ROOT_BINARY_DIR ${CMAKE_BINARY_DIR}/${TNG_ROOT_BINARY_DIR})
 
 function (TNG_GENERATE_VERSION_H)
     set(TNG_MAJOR_VERSION "1")
     set(TNG_MINOR_VERSION "7")
-    set(TNG_VERSION_PATCH_LEVEL "6")
+    set(TNG_VERSION_PATCH_LEVEL "9")
     set(TNG_IO_VERSION "${TNG_MAJOR_VERSION}.${TNG_MINOR_VERSION}.${TNG_VERSION_PATCH_LEVEL}")
     set(TNG_API_VERSION "7")
     configure_file(${TNG_ROOT_SOURCE_DIR}/include/tng/version.h.in
@@ -15,52 +18,86 @@ function (TNG_GENERATE_VERSION_H)
     set(TNG_IO_VERSION ${TNG_IO_VERSION} PARENT_SCOPE)
 endfunction()
 
-tng_generate_version_h()
-
 include(TestBigEndian)
 test_big_endian(TNG_INTEGER_BIG_ENDIAN)
 include(CheckIncludeFile)
 check_include_file(inttypes.h TNG_HAVE_INTTYPES_H)
+include(CMakeParseArguments)
+
+function(add_tng_io_library NAME)
+    tng_generate_version_h()
 
-macro(TNG_GET_SOURCE_LIST TNG_SOURCELIST TNG_COMPILEDEFS)
-    include_directories(BEFORE ${TNG_ROOT_SOURCE_DIR}/include)
-    include_directories(BEFORE ${TNG_ROOT_BINARY_DIR}/include)
-    set(_tng_compression_sources bwlzh.c bwt.c coder.c dict.c fixpoint.c huffman.c huffmem.c lz77.c merge_sort.c mtf.c rle.c tng_compress.c vals16.c warnmalloc.c widemuldiv.c xtc2.c xtc3.c)
+    set(_tng_compression_sources
+        bwlzh.c bwt.c coder.c dict.c fixpoint.c huffman.c huffmem.c
+        lz77.c merge_sort.c mtf.c rle.c tng_compress.c vals16.c
+        warnmalloc.c widemuldiv.c xtc2.c xtc3.c)
     set(_tng_io_sources tng_io.c md5.c)
-    set(${TNG_SOURCELIST})
-    set(${TNG_COMPILEDEFS})
+    set(_sources)
     foreach(_file ${_tng_compression_sources})
-        list(APPEND ${TNG_SOURCELIST} ${TNG_ROOT_SOURCE_DIR}/src/compression/${_file})
+        list(APPEND _sources ${TNG_ROOT_SOURCE_DIR}/src/compression/${_file})
     endforeach()
     foreach(_file ${_tng_io_sources})
-        list(APPEND ${TNG_SOURCELIST} ${TNG_ROOT_SOURCE_DIR}/src/lib/${_file})
+        list(APPEND _sources ${TNG_ROOT_SOURCE_DIR}/src/lib/${_file})
     endforeach()
     if(TNG_BUILD_FORTRAN)
-      list(APPEND ${TNG_SOURCELIST} ${TNG_ROOT_SOURCE_DIR}/src/lib/tng_io_fortran.c)
+        list(APPEND _sources ${TNG_ROOT_SOURCE_DIR}/src/lib/tng_io_fortran.c)
     endif()
-    if (TNG_HAVE_INTTYPES_H)
-        list(APPEND ${TNG_COMPILEDEFS} USE_STD_INTTYPES_H)
+
+    set(_options OBJECT OWN_ZLIB)
+    cmake_parse_arguments(ARG "${_options}" "" "" ${ARGN})
+
+    set(_build_target ${NAME})
+    set(_link_type PRIVATE)
+    if (ARG_OBJECT)
+        set(_build_target tng_io_obj)
+        set(_link_type INTERFACE)
+        add_library(${_build_target} OBJECT ${_sources})
+        # PIC is only on by default for SHARED libraries, but in case the
+        # object library is going to get used in such a library, the objects
+        # should be compiled with PIC as well.
+        if (BUILD_SHARED_LIBS)
+            set_target_properties(${_build_target} PROPERTIES POSITION_INDEPENDENT_CODE ON)
+        endif()
+        add_library(${NAME} INTERFACE)
+        target_sources(${NAME} INTERFACE $<TARGET_OBJECTS:tng_io_obj>)
+    else()
+        add_library(${NAME} ${_sources})
+        set_target_properties(${NAME} PROPERTIES
+                              VERSION ${TNG_IO_VERSION}
+                              SOVERSION ${TNG_MAJOR_VERSION})
+        target_include_directories(${NAME} INTERFACE $<INSTALL_INTERFACE:include>)
     endif()
-endmacro()
+    target_include_directories(${_build_target} PRIVATE
+                               $<BUILD_INTERFACE:${TNG_ROOT_SOURCE_DIR}/include>
+                               $<BUILD_INTERFACE:${TNG_ROOT_BINARY_DIR}/include>)
+    target_include_directories(${NAME} INTERFACE
+                               $<BUILD_INTERFACE:${TNG_ROOT_SOURCE_DIR}/include>
+                               $<BUILD_INTERFACE:${TNG_ROOT_BINARY_DIR}/include>)
 
-macro(TNG_SET_SOURCE_PROPERTIES)
-    set(_tng_with_zlib OFF)
-    set(_curr_var)
-    foreach (_arg ${ARGN})
-        if (_arg STREQUAL "WITH_ZLIB")
-            set(_curr_var with_zlib)
-        elseif (_curr_var)
-            set(_tng_${_curr_var} ${_arg})
-            set(_curr_var "")
-        else()
-            message(FATAL_ERROR "Invalid argument ${_arg} to TNG_SET_SOURCE_PROPERTIES")
+    if (UNIX)
+        target_link_libraries(${NAME} ${_link_type} m)
+    endif()
+
+    if (ARG_OWN_ZLIB)
+        set(_zlib_dir ${TNG_ROOT_SOURCE_DIR}/external/zlib)
+        set(_zlib_sources)
+        # Add minimal necessary number of TNG source files
+        foreach(_file adler32.c compress.c crc32.c deflate.c inffast.c inflate.c inftrees.c trees.c uncompr.c zutil.c)
+            list(APPEND _zlib_sources ${_zlib_dir}/${_file})
+        endforeach()
+        add_library(tng_io_zlib OBJECT ${_zlib_sources})
+        if (BUILD_SHARED_LIBS)
+            set_target_properties(tng_io_zlib PROPERTIES POSITION_INDEPENDENT_CODE ON)
         endif()
-    endforeach()
-    if (_tng_with_zlib)
-        set_property(SOURCE ${TNG_ROOT_SOURCE_DIR}/src/lib/tng_io.c
-                     APPEND PROPERTY COMPILE_DEFINITIONS USE_ZLIB)
+        target_include_directories(tng_io_zlib PUBLIC ${_zlib_dir})
+        target_include_directories(${_build_target} PRIVATE ${_zlib_dir})
+        target_sources(${NAME} ${_link_type} $<TARGET_OBJECTS:tng_io_zlib>)
+    else()
+        target_link_libraries(${NAME} ${_link_type} ZLIB::ZLIB)
     endif()
+
     if (TNG_HAVE_INTTYPES_H)
+        target_compile_definitions(${NAME} INTERFACE USE_STD_INTTYPES_H)
         set_property(SOURCE ${TNG_ROOT_SOURCE_DIR}/src/lib/tng_io.c
                      APPEND PROPERTY COMPILE_DEFINITIONS USE_STD_INTTYPES_H)
     endif()
@@ -68,4 +105,4 @@ macro(TNG_SET_SOURCE_PROPERTIES)
         set_property(SOURCE ${TNG_ROOT_SOURCE_DIR}/src/lib/md5.c
                      APPEND PROPERTY COMPILE_DEFINITIONS TNG_INTEGER_BIG_ENDIAN)
     endif()
-endmacro()
+endfunction()
index 87c10be8be43ef8f6fdda77ec6536a176f62711f..0fb5be3a9dbc8840276eca152ebb000b48f6eb53 100644 (file)
@@ -1,8 +1,7 @@
-cmake_minimum_required(VERSION 2.8.8)
+cmake_minimum_required(VERSION 3.1)
 
 project(TNG_IO)
 
-
 if("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
     set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wall")
 elseif(WIN32)
@@ -10,6 +9,7 @@ elseif(WIN32)
 endif()
 
 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
 set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
 
 option(BUILD_SHARED_LIBS "Enable shared libraries" ON)
@@ -20,53 +20,47 @@ option(TNG_BUILD_EXAMPLES "Build examples showing usage of the TNG API" ON)
 option(TNG_BUILD_TEST "Build TNG testing binary." ON)
 option(TNG_BUILD_COMPRESSION_TESTS "Build tests of the TNG compression library" OFF)
 
-find_package(ZLIB QUIET)
-option(TNG_BUILD_WITH_ZLIB "Build TNG with zlib compression" ${ZLIB_FOUND})
+option(TNG_BUILD_OWN_ZLIB "Build and use the internal zlib library" OFF)
+if(NOT TNG_BUILD_OWN_ZLIB)
+  find_package(ZLIB QUIET)
+endif()
 
 include(CheckIncludeFile)
 check_include_file(inttypes.h   HAVE_INTTYPES_H)
 
 include(BuildTNG.cmake)
-tng_get_source_list(TNG_SOURCES TNG_COMPILE_DEFS)
-
-tng_set_source_properties(WITH_ZLIB ${ZLIB_FOUND})
-
-add_library(tng_io ${TNG_SOURCES})
-
-if (ZLIB_FOUND)
-  list(APPEND EXTRA_LIBRARIES ${ZLIB_LIBRARIES})
-  include_directories(${ZLIB_INCLUDE_DIRS})
-endif()
-
-if (UNIX)
-  list(APPEND EXTRA_LIBRARIES m)
+if (ZLIB_FOUND AND NOT TNG_BUILD_OWN_ZLIB)
+  add_tng_io_library(tng_io)
+else()
+  add_tng_io_library(tng_io OWN_ZLIB)
 endif()
 
-target_link_libraries(tng_io ${EXTRA_LIBRARIES})
-
-set_target_properties(tng_io PROPERTIES VERSION ${TNG_IO_VERSION} SOVERSION ${TNG_MAJOR_VERSION})
+# Use GNUInstallDirs to set paths on multiarch systems
+include(GNUInstallDirs)
 
 # Create the tng_ioConfig.cmake and tng_ioConfigVersion.cmake files for the install tree
-set(CONF_INCLUDE_DIRS "${CMAKE_INSTALL_PREFIX}/include")
 configure_file(              src/lib/tng_io-config.cmake.in
   "${CMAKE_CURRENT_BINARY_DIR}/cmake/tng_io-config.cmake" @ONLY)
 configure_file(              src/lib/tng_io-configVersion.cmake.in
   "${CMAKE_CURRENT_BINARY_DIR}/cmake/tng_io-configVersion.cmake" @ONLY)
 
-# Use GNUInstallDirst to set paths on multiarch systems
-include(GNUInstallDirs)
+install(TARGETS tng_io
+        EXPORT tng_io
+        LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+        ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}")
 
-# Install the tng_ioConfig.cmake and tng_ioConfigVersion.cmake
-install(FILES
-  "${CMAKE_CURRENT_BINARY_DIR}/cmake/tng_io-config.cmake"
-  "${CMAKE_CURRENT_BINARY_DIR}/cmake/tng_io-configVersion.cmake"
-  DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/tng_io")
+install(EXPORT tng_io FILE tng_io.cmake
+        NAMESPACE tng_io::
+        DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/tng_io")
 
-install(TARGETS tng_io
-        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
-        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
+install(FILES
+        "${CMAKE_CURRENT_BINARY_DIR}/cmake/tng_io-config.cmake"
+        "${CMAKE_CURRENT_BINARY_DIR}/cmake/tng_io-configVersion.cmake"
+        DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/tng_io")
 
-install(FILES include/tng/tng_io.h include/tng/tng_io_fwd.h ${CMAKE_CURRENT_BINARY_DIR}/include/tng/version.h
+install(FILES
+        include/tng/tng_io.h include/tng/tng_io_fwd.h
+        ${CMAKE_CURRENT_BINARY_DIR}/include/tng/version.h
         DESTINATION include/tng)
 
 #-- Add an Option to toggle the generation of the API documentation
@@ -92,4 +86,3 @@ if(TNG_BUILD_DOCUMENTATION)
 endif()
 
 add_subdirectory(src)
-
diff --git a/src/external/tng_io/external/README b/src/external/tng_io/external/README
new file mode 100644 (file)
index 0000000..edff146
--- /dev/null
@@ -0,0 +1,10 @@
+The libraries included in the external directory are not supported by the TNG developers.
+
+zlib: version 1.2.8, with content not necessary for TNG build removed.
+
+Modifications within source files were
+* minor refactoring in crc32.c to make clear that some code should sometimes be unreachable
+* replacing some undefined behaviour (-1L << 16) with well defined value (~0xFFFFL) in inflate.c
+* commenting out unused zlibCompileFlags() declaration and definition
+* removing unnecessary configurability from zconf.h
+* removing #include of unused gzguts.h
diff --git a/src/external/tng_io/external/zlib/README b/src/external/tng_io/external/zlib/README
new file mode 100644 (file)
index 0000000..5ca9d12
--- /dev/null
@@ -0,0 +1,115 @@
+ZLIB DATA COMPRESSION LIBRARY
+
+zlib 1.2.8 is a general purpose data compression library.  All the code is
+thread safe.  The data format used by the zlib library is described by RFCs
+(Request for Comments) 1950 to 1952 in the files
+http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and
+rfc1952 (gzip format).
+
+All functions of the compression library are documented in the file zlib.h
+(volunteer to write man pages welcome, contact zlib@gzip.org).  A usage example
+of the library is given in the file test/example.c which also tests that
+the library is working correctly.  Another example is given in the file
+test/minigzip.c.  The compression library itself is composed of all source
+files in the root directory.
+
+To compile all files and run the test program, follow the instructions given at
+the top of Makefile.in.  In short "./configure; make test", and if that goes
+well, "make install" should work for most flavors of Unix.  For Windows, use
+one of the special makefiles in win32/ or contrib/vstudio/ .  For VMS, use
+make_vms.com.
+
+Questions about zlib should be sent to <zlib@gzip.org>, or to Gilles Vollant
+<info@winimage.com> for the Windows DLL version.  The zlib home page is
+http://zlib.net/ .  Before reporting a problem, please check this site to
+verify that you have the latest version of zlib; otherwise get the latest
+version and check whether the problem still exists or not.
+
+PLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help.
+
+Mark Nelson <markn@ieee.org> wrote an article about zlib for the Jan.  1997
+issue of Dr.  Dobb's Journal; a copy of the article is available at
+http://marknelson.us/1997/01/01/zlib-engine/ .
+
+The changes made in version 1.2.8 are documented in the file ChangeLog.
+
+Unsupported third party contributions are provided in directory contrib/ .
+
+zlib is available in Java using the java.util.zip package, documented at
+http://java.sun.com/developer/technicalArticles/Programming/compression/ .
+
+A Perl interface to zlib written by Paul Marquess <pmqs@cpan.org> is available
+at CPAN (Comprehensive Perl Archive Network) sites, including
+http://search.cpan.org/~pmqs/IO-Compress-Zlib/ .
+
+A Python interface to zlib written by A.M. Kuchling <amk@amk.ca> is
+available in Python 1.5 and later versions, see
+http://docs.python.org/library/zlib.html .
+
+zlib is built into tcl: http://wiki.tcl.tk/4610 .
+
+An experimental package to read and write files in .zip format, written on top
+of zlib by Gilles Vollant <info@winimage.com>, is available in the
+contrib/minizip directory of zlib.
+
+
+Notes for some targets:
+
+- For Windows DLL versions, please see win32/DLL_FAQ.txt
+
+- For 64-bit Irix, deflate.c must be compiled without any optimization. With
+  -O, one libpng test fails. The test works in 32 bit mode (with the -n32
+  compiler flag). The compiler bug has been reported to SGI.
+
+- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works
+  when compiled with cc.
+
+- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is
+  necessary to get gzprintf working correctly. This is done by configure.
+
+- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with
+  other compilers. Use "make test" to check your compiler.
+
+- gzdopen is not supported on RISCOS or BEOS.
+
+- For PalmOs, see http://palmzlib.sourceforge.net/
+
+
+Acknowledgments:
+
+  The deflate format used by zlib was defined by Phil Katz.  The deflate and
+  zlib specifications were written by L.  Peter Deutsch.  Thanks to all the
+  people who reported problems and suggested various improvements in zlib; they
+  are too numerous to cite here.
+
+Copyright notice:
+
+ (C) 1995-2013 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup@gzip.org          madler@alumni.caltech.edu
+
+If you use the zlib library in a product, we would appreciate *not* receiving
+lengthy legal documents to sign.  The sources are provided for free but without
+warranty of any kind.  The library has been entirely written by Jean-loup
+Gailly and Mark Adler; it does not include third-party code.
+
+If you redistribute modified sources, we would appreciate that you include in
+the file ChangeLog history information documenting your changes.  Please read
+the FAQ for more information on the distribution of modified source versions.
diff --git a/src/external/tng_io/external/zlib/adler32.c b/src/external/tng_io/external/zlib/adler32.c
new file mode 100644 (file)
index 0000000..a868f07
--- /dev/null
@@ -0,0 +1,179 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-2011 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zutil.h"
+
+#define local static
+
+local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2));
+
+#define BASE 65521      /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
+#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf)   DO8(buf,0); DO8(buf,8);
+
+/* use NO_DIVIDE if your processor does not do division in hardware --
+   try it both ways to see which is faster */
+#ifdef NO_DIVIDE
+/* note that this assumes BASE is 65521, where 65536 % 65521 == 15
+   (thank you to John Reiser for pointing this out) */
+#  define CHOP(a) \
+    do { \
+        unsigned long tmp = a >> 16; \
+        a &= 0xffffUL; \
+        a += (tmp << 4) - tmp; \
+    } while (0)
+#  define MOD28(a) \
+    do { \
+        CHOP(a); \
+        if (a >= BASE) a -= BASE; \
+    } while (0)
+#  define MOD(a) \
+    do { \
+        CHOP(a); \
+        MOD28(a); \
+    } while (0)
+#  define MOD63(a) \
+    do { /* this assumes a is not negative */ \
+        z_off64_t tmp = a >> 32; \
+        a &= 0xffffffffL; \
+        a += (tmp << 8) - (tmp << 5) + tmp; \
+        tmp = a >> 16; \
+        a &= 0xffffL; \
+        a += (tmp << 4) - tmp; \
+        tmp = a >> 16; \
+        a &= 0xffffL; \
+        a += (tmp << 4) - tmp; \
+        if (a >= BASE) a -= BASE; \
+    } while (0)
+#else
+#  define MOD(a) a %= BASE
+#  define MOD28(a) a %= BASE
+#  define MOD63(a) a %= BASE
+#endif
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+    uLong adler;
+    const Bytef *buf;
+    uInt len;
+{
+    unsigned long sum2;
+    unsigned n;
+
+    /* split Adler-32 into component sums */
+    sum2 = (adler >> 16) & 0xffff;
+    adler &= 0xffff;
+
+    /* in case user likes doing a byte at a time, keep it fast */
+    if (len == 1) {
+        adler += buf[0];
+        if (adler >= BASE)
+            adler -= BASE;
+        sum2 += adler;
+        if (sum2 >= BASE)
+            sum2 -= BASE;
+        return adler | (sum2 << 16);
+    }
+
+    /* initial Adler-32 value (deferred check for len == 1 speed) */
+    if (buf == Z_NULL)
+        return 1L;
+
+    /* in case short lengths are provided, keep it somewhat fast */
+    if (len < 16) {
+        while (len--) {
+            adler += *buf++;
+            sum2 += adler;
+        }
+        if (adler >= BASE)
+            adler -= BASE;
+        MOD28(sum2);            /* only added so many BASE's */
+        return adler | (sum2 << 16);
+    }
+
+    /* do length NMAX blocks -- requires just one modulo operation */
+    while (len >= NMAX) {
+        len -= NMAX;
+        n = NMAX / 16;          /* NMAX is divisible by 16 */
+        do {
+            DO16(buf);          /* 16 sums unrolled */
+            buf += 16;
+        } while (--n);
+        MOD(adler);
+        MOD(sum2);
+    }
+
+    /* do remaining bytes (less than NMAX, still just one modulo) */
+    if (len) {                  /* avoid modulos if none remaining */
+        while (len >= 16) {
+            len -= 16;
+            DO16(buf);
+            buf += 16;
+        }
+        while (len--) {
+            adler += *buf++;
+            sum2 += adler;
+        }
+        MOD(adler);
+        MOD(sum2);
+    }
+
+    /* return recombined sums */
+    return adler | (sum2 << 16);
+}
+
+/* ========================================================================= */
+local uLong adler32_combine_(adler1, adler2, len2)
+    uLong adler1;
+    uLong adler2;
+    z_off64_t len2;
+{
+    unsigned long sum1;
+    unsigned long sum2;
+    unsigned rem;
+
+    /* for negative len, return invalid adler32 as a clue for debugging */
+    if (len2 < 0)
+        return 0xffffffffUL;
+
+    /* the derivation of this formula is left as an exercise for the reader */
+    MOD63(len2);                /* assumes len2 >= 0 */
+    rem = (unsigned)len2;
+    sum1 = adler1 & 0xffff;
+    sum2 = rem * sum1;
+    MOD(sum2);
+    sum1 += (adler2 & 0xffff) + BASE - 1;
+    sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
+    if (sum1 >= BASE) sum1 -= BASE;
+    if (sum1 >= BASE) sum1 -= BASE;
+    if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1);
+    if (sum2 >= BASE) sum2 -= BASE;
+    return sum1 | (sum2 << 16);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT adler32_combine(adler1, adler2, len2)
+    uLong adler1;
+    uLong adler2;
+    z_off_t len2;
+{
+    return adler32_combine_(adler1, adler2, len2);
+}
+
+uLong ZEXPORT adler32_combine64(adler1, adler2, len2)
+    uLong adler1;
+    uLong adler2;
+    z_off64_t len2;
+{
+    return adler32_combine_(adler1, adler2, len2);
+}
diff --git a/src/external/tng_io/external/zlib/compress.c b/src/external/tng_io/external/zlib/compress.c
new file mode 100644 (file)
index 0000000..6e97626
--- /dev/null
@@ -0,0 +1,80 @@
+/* compress.c -- compress a memory buffer
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+     Compresses the source buffer into the destination buffer. The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer. Upon entry, destLen is the total size of the
+   destination buffer, which must be at least 0.1% larger than sourceLen plus
+   12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+    int level;
+{
+    z_stream stream;
+    int err;
+
+    stream.next_in = (z_const Bytef *)source;
+    stream.avail_in = (uInt)sourceLen;
+#ifdef MAXSEG_64K
+    /* Check for source > 64K on 16-bit machine: */
+    if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+#endif
+    stream.next_out = dest;
+    stream.avail_out = (uInt)*destLen;
+    if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+    stream.zalloc = (alloc_func)0;
+    stream.zfree = (free_func)0;
+    stream.opaque = (voidpf)0;
+
+    err = deflateInit(&stream, level);
+    if (err != Z_OK) return err;
+
+    err = deflate(&stream, Z_FINISH);
+    if (err != Z_STREAM_END) {
+        deflateEnd(&stream);
+        return err == Z_OK ? Z_BUF_ERROR : err;
+    }
+    *destLen = stream.total_out;
+
+    err = deflateEnd(&stream);
+    return err;
+}
+
+/* ===========================================================================
+ */
+int ZEXPORT compress (dest, destLen, source, sourceLen)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+{
+    return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
+}
+
+/* ===========================================================================
+     If the default memLevel or windowBits for deflateInit() is changed, then
+   this function needs to be updated.
+ */
+uLong ZEXPORT compressBound (sourceLen)
+    uLong sourceLen;
+{
+    return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
+           (sourceLen >> 25) + 13;
+}
diff --git a/src/external/tng_io/external/zlib/crc32.c b/src/external/tng_io/external/zlib/crc32.c
new file mode 100644 (file)
index 0000000..e513833
--- /dev/null
@@ -0,0 +1,430 @@
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-2006, 2010, 2011, 2012 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
+ * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
+ * tables for updating the shift register in one step with three exclusive-ors
+ * instead of four steps with four exclusive-ors.  This results in about a
+ * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
+ */
+
+/* @(#) $Id$ */
+
+/*
+  Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore
+  protection on the static variables used to control the first-use generation
+  of the crc tables.  Therefore, if you #define DYNAMIC_CRC_TABLE, you should
+  first call get_crc_table() to initialize the tables before allowing more than
+  one thread to use crc32().
+
+  DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h.
+ */
+
+#ifdef MAKECRCH
+#  include <stdio.h>
+#  ifndef DYNAMIC_CRC_TABLE
+#    define DYNAMIC_CRC_TABLE
+#  endif /* !DYNAMIC_CRC_TABLE */
+#endif /* MAKECRCH */
+
+#include "zutil.h"      /* for STDC and FAR definitions */
+
+#define local static
+
+/* Definitions for doing the crc four data bytes at a time. */
+#if !defined(NOBYFOUR) && defined(Z_U4)
+#  define BYFOUR
+#endif
+#ifdef BYFOUR
+   local unsigned long crc32_little OF((unsigned long,
+                        const unsigned char FAR *, unsigned));
+   local unsigned long crc32_big OF((unsigned long,
+                        const unsigned char FAR *, unsigned));
+#  define TBLS 8
+#else
+#  define TBLS 1
+#endif /* BYFOUR */
+
+/* Local functions for crc concatenation */
+local unsigned long gf2_matrix_times OF((unsigned long *mat,
+                                         unsigned long vec));
+local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat));
+local uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2));
+
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local volatile int crc_table_empty = 1;
+local z_crc_t FAR crc_table[TBLS][256];
+local void make_crc_table OF((void));
+#ifdef MAKECRCH
+   local void write_table OF((FILE *, const z_crc_t FAR *));
+#endif /* MAKECRCH */
+/*
+  Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
+  x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+  Polynomials over GF(2) are represented in binary, one bit per coefficient,
+  with the lowest powers in the most significant bit.  Then adding polynomials
+  is just exclusive-or, and multiplying a polynomial by x is a right shift by
+  one.  If we call the above polynomial p, and represent a byte as the
+  polynomial q, also with the lowest power in the most significant bit (so the
+  byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+  where a mod b means the remainder after dividing a by b.
+
+  This calculation is done using the shift-register method of multiplying and
+  taking the remainder.  The register is initialized to zero, and for each
+  incoming bit, x^32 is added mod p to the register if the bit is a one (where
+  x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+  x (which is shifting right by one and adding x^32 mod p if the bit shifted
+  out is a one).  We start with the highest power (least significant bit) of
+  q and repeat for all eight bits of q.
+
+  The first table is simply the CRC of all possible eight bit values.  This is
+  all the information needed to generate CRCs on data a byte at a time for all
+  combinations of CRC register values and incoming bytes.  The remaining tables
+  allow for word-at-a-time CRC calculation for both big-endian and little-
+  endian machines, where a word is four bytes.
+*/
+local void make_crc_table()
+{
+    z_crc_t c;
+    int n, k;
+    z_crc_t poly;                       /* polynomial exclusive-or pattern */
+    /* terms of polynomial defining this crc (except x^32): */
+    static volatile int first = 1;      /* flag to limit concurrent making */
+    static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+    /* See if another task is already doing this (not thread-safe, but better
+       than nothing -- significantly reduces duration of vulnerability in
+       case the advice about DYNAMIC_CRC_TABLE is ignored) */
+    if (first) {
+        first = 0;
+
+        /* make exclusive-or pattern from polynomial (0xedb88320UL) */
+        poly = 0;
+        for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++)
+            poly |= (z_crc_t)1 << (31 - p[n]);
+
+        /* generate a crc for every 8-bit value */
+        for (n = 0; n < 256; n++) {
+            c = (z_crc_t)n;
+            for (k = 0; k < 8; k++)
+                c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+            crc_table[0][n] = c;
+        }
+
+#ifdef BYFOUR
+        /* generate crc for each value followed by one, two, and three zeros,
+           and then the byte reversal of those as well as the first table */
+        for (n = 0; n < 256; n++) {
+            c = crc_table[0][n];
+            crc_table[4][n] = ZSWAP32(c);
+            for (k = 1; k < 4; k++) {
+                c = crc_table[0][c & 0xff] ^ (c >> 8);
+                crc_table[k][n] = c;
+                crc_table[k + 4][n] = ZSWAP32(c);
+            }
+        }
+#endif /* BYFOUR */
+
+        crc_table_empty = 0;
+    }
+    else {      /* not first */
+        /* wait for the other guy to finish (not efficient, but rare) */
+        while (crc_table_empty)
+            ;
+    }
+
+#ifdef MAKECRCH
+    /* write out CRC tables to crc32.h */
+    {
+        FILE *out;
+
+        out = fopen("crc32.h", "w");
+        if (out == NULL) return;
+        fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n");
+        fprintf(out, " * Generated automatically by crc32.c\n */\n\n");
+        fprintf(out, "local const z_crc_t FAR ");
+        fprintf(out, "crc_table[TBLS][256] =\n{\n  {\n");
+        write_table(out, crc_table[0]);
+#  ifdef BYFOUR
+        fprintf(out, "#ifdef BYFOUR\n");
+        for (k = 1; k < 8; k++) {
+            fprintf(out, "  },\n  {\n");
+            write_table(out, crc_table[k]);
+        }
+        fprintf(out, "#endif\n");
+#  endif /* BYFOUR */
+        fprintf(out, "  }\n};\n");
+        fclose(out);
+    }
+#endif /* MAKECRCH */
+}
+
+#ifdef MAKECRCH
+local void write_table(out, table)
+    FILE *out;
+    const z_crc_t FAR *table;
+{
+    int n;
+
+    for (n = 0; n < 256; n++)
+        fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : "    ",
+                (unsigned long)(table[n]),
+                n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", "));
+}
+#endif /* MAKECRCH */
+
+#else /* !DYNAMIC_CRC_TABLE */
+/* ========================================================================
+ * Tables of CRC-32s of all single-byte values, made by make_crc_table().
+ */
+#include "crc32.h"
+#endif /* DYNAMIC_CRC_TABLE */
+
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const z_crc_t FAR * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+    if (crc_table_empty)
+        make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+    return (const z_crc_t FAR *)crc_table;
+}
+
+/* ========================================================================= */
+#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
+#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
+
+/* ========================================================================= */
+unsigned long ZEXPORT crc32(crc, buf, len)
+    unsigned long crc;
+    const unsigned char FAR *buf;
+    uInt len;
+{
+    if (buf == Z_NULL) return 0UL;
+
+#ifdef DYNAMIC_CRC_TABLE
+    if (crc_table_empty)
+        make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+
+#ifdef BYFOUR
+    if (sizeof(void *) == sizeof(ptrdiff_t)) {
+        z_crc_t endian;
+
+        endian = 1;
+        if (*((unsigned char *)(&endian)))
+            return crc32_little(crc, buf, len);
+        else
+            return crc32_big(crc, buf, len);
+    }
+    /* Minor modifications follow that make clear to compilers that
+     * it is intended that some code is unreachable. */
+    else
+#endif /* BYFOUR */
+    {
+        crc = crc ^ 0xffffffffUL;
+        while (len >= 8) {
+            DO8;
+            len -= 8;
+        }
+        if (len) do {
+                DO1;
+            } while (--len);
+        return crc ^ 0xffffffffUL;
+    }
+}
+
+#ifdef BYFOUR
+
+/* ========================================================================= */
+#define DOLIT4 c ^= *buf4++; \
+        c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
+            crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
+#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
+
+/* ========================================================================= */
+local unsigned long crc32_little(crc, buf, len)
+    unsigned long crc;
+    const unsigned char FAR *buf;
+    unsigned len;
+{
+    register z_crc_t c;
+    register const z_crc_t FAR *buf4;
+
+    c = (z_crc_t)crc;
+    c = ~c;
+    while (len && ((ptrdiff_t)buf & 3)) {
+        c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+        len--;
+    }
+
+    buf4 = (const z_crc_t FAR *)(const void FAR *)buf;
+    while (len >= 32) {
+        DOLIT32;
+        len -= 32;
+    }
+    while (len >= 4) {
+        DOLIT4;
+        len -= 4;
+    }
+    buf = (const unsigned char FAR *)buf4;
+
+    if (len) do {
+        c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+    } while (--len);
+    c = ~c;
+    return (unsigned long)c;
+}
+
+/* ========================================================================= */
+#define DOBIG4 c ^= *++buf4; \
+        c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
+            crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
+#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
+
+/* ========================================================================= */
+local unsigned long crc32_big(crc, buf, len)
+    unsigned long crc;
+    const unsigned char FAR *buf;
+    unsigned len;
+{
+    register z_crc_t c;
+    register const z_crc_t FAR *buf4;
+
+    c = ZSWAP32((z_crc_t)crc);
+    c = ~c;
+    while (len && ((ptrdiff_t)buf & 3)) {
+        c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+        len--;
+    }
+
+    buf4 = (const z_crc_t FAR *)(const void FAR *)buf;
+    buf4--;
+    while (len >= 32) {
+        DOBIG32;
+        len -= 32;
+    }
+    while (len >= 4) {
+        DOBIG4;
+        len -= 4;
+    }
+    buf4++;
+    buf = (const unsigned char FAR *)buf4;
+
+    if (len) do {
+        c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+    } while (--len);
+    c = ~c;
+    return (unsigned long)(ZSWAP32(c));
+}
+
+#endif /* BYFOUR */
+
+#define GF2_DIM 32      /* dimension of GF(2) vectors (length of CRC) */
+
+/* ========================================================================= */
+local unsigned long gf2_matrix_times(mat, vec)
+    unsigned long *mat;
+    unsigned long vec;
+{
+    unsigned long sum;
+
+    sum = 0;
+    while (vec) {
+        if (vec & 1)
+            sum ^= *mat;
+        vec >>= 1;
+        mat++;
+    }
+    return sum;
+}
+
+/* ========================================================================= */
+local void gf2_matrix_square(square, mat)
+    unsigned long *square;
+    unsigned long *mat;
+{
+    int n;
+
+    for (n = 0; n < GF2_DIM; n++)
+        square[n] = gf2_matrix_times(mat, mat[n]);
+}
+
+/* ========================================================================= */
+local uLong crc32_combine_(crc1, crc2, len2)
+    uLong crc1;
+    uLong crc2;
+    z_off64_t len2;
+{
+    int n;
+    unsigned long row;
+    unsigned long even[GF2_DIM];    /* even-power-of-two zeros operator */
+    unsigned long odd[GF2_DIM];     /* odd-power-of-two zeros operator */
+
+    /* degenerate case (also disallow negative lengths) */
+    if (len2 <= 0)
+        return crc1;
+
+    /* put operator for one zero bit in odd */
+    odd[0] = 0xedb88320UL;          /* CRC-32 polynomial */
+    row = 1;
+    for (n = 1; n < GF2_DIM; n++) {
+        odd[n] = row;
+        row <<= 1;
+    }
+
+    /* put operator for two zero bits in even */
+    gf2_matrix_square(even, odd);
+
+    /* put operator for four zero bits in odd */
+    gf2_matrix_square(odd, even);
+
+    /* apply len2 zeros to crc1 (first square will put the operator for one
+       zero byte, eight zero bits, in even) */
+    do {
+        /* apply zeros operator for this bit of len2 */
+        gf2_matrix_square(even, odd);
+        if (len2 & 1)
+            crc1 = gf2_matrix_times(even, crc1);
+        len2 >>= 1;
+
+        /* if no more bits set, then done */
+        if (len2 == 0)
+            break;
+
+        /* another iteration of the loop with odd and even swapped */
+        gf2_matrix_square(odd, even);
+        if (len2 & 1)
+            crc1 = gf2_matrix_times(odd, crc1);
+        len2 >>= 1;
+
+        /* if no more bits set, then done */
+    } while (len2 != 0);
+
+    /* return combined crc */
+    crc1 ^= crc2;
+    return crc1;
+}
+
+/* ========================================================================= */
+uLong ZEXPORT crc32_combine(crc1, crc2, len2)
+    uLong crc1;
+    uLong crc2;
+    z_off_t len2;
+{
+    return crc32_combine_(crc1, crc2, len2);
+}
+
+uLong ZEXPORT crc32_combine64(crc1, crc2, len2)
+    uLong crc1;
+    uLong crc2;
+    z_off64_t len2;
+{
+    return crc32_combine_(crc1, crc2, len2);
+}
diff --git a/src/external/tng_io/external/zlib/crc32.h b/src/external/tng_io/external/zlib/crc32.h
new file mode 100644 (file)
index 0000000..9e0c778
--- /dev/null
@@ -0,0 +1,441 @@
+/* crc32.h -- tables for rapid CRC calculation
+ * Generated automatically by crc32.c
+ */
+
+local const z_crc_t FAR crc_table[TBLS][256] =
+{
+  {
+    0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
+    0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
+    0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
+    0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
+    0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
+    0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
+    0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
+    0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
+    0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
+    0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
+    0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
+    0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
+    0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
+    0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
+    0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
+    0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
+    0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
+    0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
+    0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
+    0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
+    0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
+    0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
+    0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
+    0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
+    0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
+    0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
+    0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
+    0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
+    0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
+    0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
+    0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
+    0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
+    0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
+    0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
+    0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
+    0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
+    0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
+    0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
+    0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
+    0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
+    0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
+    0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
+    0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
+    0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
+    0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
+    0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
+    0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
+    0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
+    0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
+    0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
+    0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
+    0x2d02ef8dUL
+#ifdef BYFOUR
+  },
+  {
+    0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,
+    0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,
+    0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,
+    0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,
+    0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,
+    0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,
+    0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,
+    0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,
+    0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,
+    0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,
+    0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,
+    0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,
+    0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,
+    0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,
+    0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,
+    0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,
+    0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,
+    0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,
+    0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,
+    0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,
+    0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,
+    0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,
+    0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,
+    0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,
+    0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,
+    0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,
+    0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,
+    0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,
+    0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,
+    0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,
+    0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,
+    0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,
+    0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,
+    0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,
+    0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,
+    0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,
+    0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,
+    0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,
+    0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,
+    0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,
+    0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,
+    0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,
+    0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,
+    0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,
+    0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,
+    0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,
+    0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,
+    0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,
+    0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,
+    0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,
+    0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,
+    0x9324fd72UL
+  },
+  {
+    0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,
+    0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,
+    0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,
+    0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,
+    0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,
+    0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,
+    0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,
+    0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,
+    0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,
+    0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,
+    0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,
+    0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,
+    0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,
+    0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,
+    0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,
+    0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,
+    0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,
+    0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,
+    0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,
+    0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,
+    0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,
+    0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,
+    0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,
+    0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,
+    0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,
+    0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,
+    0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,
+    0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,
+    0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,
+    0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,
+    0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,
+    0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,
+    0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,
+    0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,
+    0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,
+    0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,
+    0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,
+    0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,
+    0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,
+    0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,
+    0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,
+    0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,
+    0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,
+    0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,
+    0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,
+    0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,
+    0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,
+    0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,
+    0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,
+    0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,
+    0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,
+    0xbe9834edUL
+  },
+  {
+    0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,
+    0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,
+    0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,
+    0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,
+    0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,
+    0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,
+    0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,
+    0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,
+    0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,
+    0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,
+    0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,
+    0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,
+    0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,
+    0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,
+    0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,
+    0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,
+    0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,
+    0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,
+    0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,
+    0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,
+    0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,
+    0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,
+    0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,
+    0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,
+    0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,
+    0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,
+    0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,
+    0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,
+    0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,
+    0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,
+    0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,
+    0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,
+    0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,
+    0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,
+    0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,
+    0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,
+    0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,
+    0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,
+    0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,
+    0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,
+    0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,
+    0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,
+    0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,
+    0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,
+    0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,
+    0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,
+    0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,
+    0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,
+    0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,
+    0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,
+    0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,
+    0xde0506f1UL
+  },
+  {
+    0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL,
+    0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL,
+    0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL,
+    0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL,
+    0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL,
+    0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL,
+    0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL,
+    0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL,
+    0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL,
+    0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL,
+    0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL,
+    0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL,
+    0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL,
+    0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL,
+    0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL,
+    0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL,
+    0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL,
+    0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL,
+    0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL,
+    0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL,
+    0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL,
+    0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL,
+    0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL,
+    0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL,
+    0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL,
+    0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL,
+    0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL,
+    0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL,
+    0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL,
+    0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL,
+    0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL,
+    0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL,
+    0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL,
+    0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL,
+    0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL,
+    0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL,
+    0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL,
+    0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL,
+    0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL,
+    0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL,
+    0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL,
+    0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL,
+    0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL,
+    0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL,
+    0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL,
+    0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL,
+    0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL,
+    0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL,
+    0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL,
+    0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL,
+    0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL,
+    0x8def022dUL
+  },
+  {
+    0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL,
+    0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL,
+    0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL,
+    0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL,
+    0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL,
+    0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL,
+    0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL,
+    0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL,
+    0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL,
+    0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL,
+    0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL,
+    0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL,
+    0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL,
+    0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL,
+    0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL,
+    0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL,
+    0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL,
+    0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL,
+    0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL,
+    0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL,
+    0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL,
+    0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL,
+    0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL,
+    0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL,
+    0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL,
+    0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL,
+    0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL,
+    0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL,
+    0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL,
+    0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL,
+    0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL,
+    0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL,
+    0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL,
+    0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL,
+    0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL,
+    0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL,
+    0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL,
+    0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL,
+    0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL,
+    0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL,
+    0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL,
+    0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL,
+    0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL,
+    0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL,
+    0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL,
+    0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL,
+    0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL,
+    0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL,
+    0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL,
+    0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL,
+    0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL,
+    0x72fd2493UL
+  },
+  {
+    0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL,
+    0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL,
+    0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL,
+    0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL,
+    0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL,
+    0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL,
+    0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL,
+    0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL,
+    0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL,
+    0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL,
+    0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL,
+    0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL,
+    0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL,
+    0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL,
+    0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL,
+    0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL,
+    0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL,
+    0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL,
+    0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL,
+    0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL,
+    0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL,
+    0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL,
+    0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL,
+    0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL,
+    0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL,
+    0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL,
+    0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL,
+    0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL,
+    0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL,
+    0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL,
+    0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL,
+    0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL,
+    0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL,
+    0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL,
+    0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL,
+    0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL,
+    0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL,
+    0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL,
+    0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL,
+    0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL,
+    0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL,
+    0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL,
+    0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL,
+    0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL,
+    0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL,
+    0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL,
+    0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL,
+    0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL,
+    0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL,
+    0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL,
+    0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL,
+    0xed3498beUL
+  },
+  {
+    0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL,
+    0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL,
+    0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL,
+    0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL,
+    0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL,
+    0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL,
+    0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL,
+    0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL,
+    0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL,
+    0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL,
+    0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL,
+    0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL,
+    0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL,
+    0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL,
+    0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL,
+    0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL,
+    0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL,
+    0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL,
+    0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL,
+    0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL,
+    0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL,
+    0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL,
+    0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL,
+    0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL,
+    0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL,
+    0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL,
+    0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL,
+    0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL,
+    0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL,
+    0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL,
+    0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL,
+    0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL,
+    0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL,
+    0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL,
+    0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL,
+    0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL,
+    0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL,
+    0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL,
+    0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL,
+    0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL,
+    0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL,
+    0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL,
+    0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL,
+    0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL,
+    0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL,
+    0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL,
+    0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL,
+    0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL,
+    0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL,
+    0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL,
+    0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL,
+    0xf10605deUL
+#endif
+  }
+};
diff --git a/src/external/tng_io/external/zlib/deflate.c b/src/external/tng_io/external/zlib/deflate.c
new file mode 100644 (file)
index 0000000..6969577
--- /dev/null
@@ -0,0 +1,1967 @@
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process depends on being able to identify portions
+ *      of the input text which are identical to earlier input (within a
+ *      sliding window trailing behind the input currently being processed).
+ *
+ *      The most straightforward technique turns out to be the fastest for
+ *      most input files: try all possible matches and select the longest.
+ *      The key feature of this algorithm is that insertions into the string
+ *      dictionary are very simple and thus fast, and deletions are avoided
+ *      completely. Insertions are performed at each input character, whereas
+ *      string matches are performed only when the previous match ends. So it
+ *      is preferable to spend more time in matches to allow very fast string
+ *      insertions and avoid deletions. The matching algorithm for small
+ *      strings is inspired from that of Rabin & Karp. A brute force approach
+ *      is used to find longer strings when a small match has been found.
+ *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ *      (by Leonid Broukhis).
+ *         A previous version of this file used a more sophisticated algorithm
+ *      (by Fiala and Greene) which is guaranteed to run in linear amortized
+ *      time, but has a larger average cost, uses more memory and is patented.
+ *      However the F&G algorithm may be faster for some highly redundant
+ *      files if the parameter max_chain_length (described below) is too large.
+ *
+ *  ACKNOWLEDGEMENTS
+ *
+ *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ *      I found it in 'freeze' written by Leonid Broukhis.
+ *      Thanks to many people for bug reports and testing.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ *      Available in http://tools.ietf.org/html/rfc1951
+ *
+ *      A description of the Rabin and Karp algorithm is given in the book
+ *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ *      Fiala,E.R., and Greene,D.H.
+ *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* @(#) $Id$ */
+
+#include "deflate.h"
+
+const char deflate_copyright[] =
+   " deflate 1.2.8 Copyright 1995-2013 Jean-loup Gailly and Mark Adler ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ *  Function prototypes.
+ */
+typedef enum {
+    need_more,      /* block not completed, need more input or more output */
+    block_done,     /* block flush performed */
+    finish_started, /* finish started, need only more output at next deflate */
+    finish_done     /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window    OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast   OF((deflate_state *s, int flush));
+#ifndef FASTEST
+local block_state deflate_slow   OF((deflate_state *s, int flush));
+#endif
+local block_state deflate_rle    OF((deflate_state *s, int flush));
+local block_state deflate_huff   OF((deflate_state *s, int flush));
+local void lm_init        OF((deflate_state *s));
+local void putShortMSB    OF((deflate_state *s, uInt b));
+local void flush_pending  OF((z_streamp strm));
+local int read_buf        OF((z_streamp strm, Bytef *buf, unsigned size));
+#ifdef ASMV
+      void match_init OF((void)); /* asm code initialization */
+      uInt longest_match  OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match  OF((deflate_state *s, IPos cur_match));
+#endif
+
+#ifdef DEBUG
+local  void check_match OF((deflate_state *s, IPos start, IPos match,
+                            int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+#  define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+   ush good_length; /* reduce lazy search above this match length */
+   ush max_lazy;    /* do not perform lazy search above this match length */
+   ush nice_length; /* quit search above this match length */
+   ush max_chain;
+   compress_func func;
+} config;
+
+#ifdef FASTEST
+local const config configuration_table[2] = {
+/*      good lazy nice chain */
+/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
+/* 1 */ {4,    4,  8,    4, deflate_fast}}; /* max speed, no lazy matches */
+#else
+local const config configuration_table[10] = {
+/*      good lazy nice chain */
+/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
+/* 1 */ {4,    4,  8,    4, deflate_fast}, /* max speed, no lazy matches */
+/* 2 */ {4,    5, 16,    8, deflate_fast},
+/* 3 */ {4,    6, 32,   32, deflate_fast},
+
+/* 4 */ {4,    4, 16,   16, deflate_slow},  /* lazy matches */
+/* 5 */ {8,   16, 32,   32, deflate_slow},
+/* 6 */ {8,   16, 128, 128, deflate_slow},
+/* 7 */ {8,   32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */
+#endif
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+#ifndef NO_DUMMY_DECL
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+#endif
+
+/* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */
+#define RANK(f) (((f) << 1) - ((f) > 4 ? 9 : 0))
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN  assertion: all calls to to UPDATE_HASH are made with consecutive
+ *    input characters, so that a running hash key can be computed from the
+ *    previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * If this file is compiled with -DFASTEST, the compression level is forced
+ * to 1, and no hash chains are maintained.
+ * IN  assertion: all calls to to INSERT_STRING are made with consecutive
+ *    input characters and the first MIN_MATCH bytes of str are valid
+ *    (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#ifdef FASTEST
+#define INSERT_STRING(s, str, match_head) \
+   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+    match_head = s->head[s->ins_h], \
+    s->head[s->ins_h] = (Pos)(str))
+#else
+#define INSERT_STRING(s, str, match_head) \
+   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+    match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \
+    s->head[s->ins_h] = (Pos)(str))
+#endif
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+    s->head[s->hash_size-1] = NIL; \
+    zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int ZEXPORT deflateInit_(strm, level, version, stream_size)
+    z_streamp strm;
+    int level;
+    const char *version;
+    int stream_size;
+{
+    return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+                         Z_DEFAULT_STRATEGY, version, stream_size);
+    /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+                  version, stream_size)
+    z_streamp strm;
+    int  level;
+    int  method;
+    int  windowBits;
+    int  memLevel;
+    int  strategy;
+    const char *version;
+    int stream_size;
+{
+    deflate_state *s;
+    int wrap = 1;
+    static const char my_version[] = ZLIB_VERSION;
+
+    ushf *overlay;
+    /* We overlay pending_buf and d_buf+l_buf. This works since the average
+     * output size for (length,distance) codes is <= 24 bits.
+     */
+
+    if (version == Z_NULL || version[0] != my_version[0] ||
+        stream_size != sizeof(z_stream)) {
+        return Z_VERSION_ERROR;
+    }
+    if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+    strm->msg = Z_NULL;
+    if (strm->zalloc == (alloc_func)0) {
+#ifdef Z_SOLO
+        return Z_STREAM_ERROR;
+#else
+        strm->zalloc = zcalloc;
+        strm->opaque = (voidpf)0;
+#endif
+    }
+    if (strm->zfree == (free_func)0)
+#ifdef Z_SOLO
+        return Z_STREAM_ERROR;
+#else
+        strm->zfree = zcfree;
+#endif
+
+#ifdef FASTEST
+    if (level != 0) level = 1;
+#else
+    if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+
+    if (windowBits < 0) { /* suppress zlib wrapper */
+        wrap = 0;
+        windowBits = -windowBits;
+    }
+#ifdef GZIP
+    else if (windowBits > 15) {
+        wrap = 2;       /* write gzip wrapper instead */
+        windowBits -= 16;
+    }
+#endif
+    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+        windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+        strategy < 0 || strategy > Z_FIXED) {
+        return Z_STREAM_ERROR;
+    }
+    if (windowBits == 8) windowBits = 9;  /* until 256-byte window bug fixed */
+    s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+    if (s == Z_NULL) return Z_MEM_ERROR;
+    strm->state = (struct internal_state FAR *)s;
+    s->strm = strm;
+
+    s->wrap = wrap;
+    s->gzhead = Z_NULL;
+    s->w_bits = windowBits;
+    s->w_size = 1 << s->w_bits;
+    s->w_mask = s->w_size - 1;
+
+    s->hash_bits = memLevel + 7;
+    s->hash_size = 1 << s->hash_bits;
+    s->hash_mask = s->hash_size - 1;
+    s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+    s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+    s->prev   = (Posf *)  ZALLOC(strm, s->w_size, sizeof(Pos));
+    s->head   = (Posf *)  ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+    s->high_water = 0;      /* nothing written to s->window yet */
+
+    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+    overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+    s->pending_buf = (uchf *) overlay;
+    s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+    if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+        s->pending_buf == Z_NULL) {
+        s->status = FINISH_STATE;
+        strm->msg = ERR_MSG(Z_MEM_ERROR);
+        deflateEnd (strm);
+        return Z_MEM_ERROR;
+    }
+    s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+    s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+    s->level = level;
+    s->strategy = strategy;
+    s->method = (Byte)method;
+
+    return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
+    z_streamp strm;
+    const Bytef *dictionary;
+    uInt  dictLength;
+{
+    deflate_state *s;
+    uInt str, n;
+    int wrap;
+    unsigned avail;
+    z_const unsigned char *next;
+
+    if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL)
+        return Z_STREAM_ERROR;
+    s = strm->state;
+    wrap = s->wrap;
+    if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead)
+        return Z_STREAM_ERROR;
+
+    /* when using zlib wrappers, compute Adler-32 for provided dictionary */
+    if (wrap == 1)
+        strm->adler = adler32(strm->adler, dictionary, dictLength);
+    s->wrap = 0;                    /* avoid computing Adler-32 in read_buf */
+
+    /* if dictionary would fill window, just replace the history */
+    if (dictLength >= s->w_size) {
+        if (wrap == 0) {            /* already empty otherwise */
+            CLEAR_HASH(s);
+            s->strstart = 0;
+            s->block_start = 0L;
+            s->insert = 0;
+        }
+        dictionary += dictLength - s->w_size;  /* use the tail */
+        dictLength = s->w_size;
+    }
+
+    /* insert dictionary into window and hash */
+    avail = strm->avail_in;
+    next = strm->next_in;
+    strm->avail_in = dictLength;
+    strm->next_in = (z_const Bytef *)dictionary;
+    fill_window(s);
+    while (s->lookahead >= MIN_MATCH) {
+        str = s->strstart;
+        n = s->lookahead - (MIN_MATCH-1);
+        do {
+            UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);
+#ifndef FASTEST
+            s->prev[str & s->w_mask] = s->head[s->ins_h];
+#endif
+            s->head[s->ins_h] = (Pos)str;
+            str++;
+        } while (--n);
+        s->strstart = str;
+        s->lookahead = MIN_MATCH-1;
+        fill_window(s);
+    }
+    s->strstart += s->lookahead;
+    s->block_start = (long)s->strstart;
+    s->insert = s->lookahead;
+    s->lookahead = 0;
+    s->match_length = s->prev_length = MIN_MATCH-1;
+    s->match_available = 0;
+    strm->next_in = next;
+    strm->avail_in = avail;
+    s->wrap = wrap;
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateResetKeep (strm)
+    z_streamp strm;
+{
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL ||
+        strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) {
+        return Z_STREAM_ERROR;
+    }
+
+    strm->total_in = strm->total_out = 0;
+    strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+    strm->data_type = Z_UNKNOWN;
+
+    s = (deflate_state *)strm->state;
+    s->pending = 0;
+    s->pending_out = s->pending_buf;
+
+    if (s->wrap < 0) {
+        s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */
+    }
+    s->status = s->wrap ? INIT_STATE : BUSY_STATE;
+    strm->adler =
+#ifdef GZIP
+        s->wrap == 2 ? crc32(0L, Z_NULL, 0) :
+#endif
+        adler32(0L, Z_NULL, 0);
+    s->last_flush = Z_NO_FLUSH;
+
+    _tr_init(s);
+
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateReset (strm)
+    z_streamp strm;
+{
+    int ret;
+
+    ret = deflateResetKeep(strm);
+    if (ret == Z_OK)
+        lm_init(strm->state);
+    return ret;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetHeader (strm, head)
+    z_streamp strm;
+    gz_headerp head;
+{
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    if (strm->state->wrap != 2) return Z_STREAM_ERROR;
+    strm->state->gzhead = head;
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflatePending (strm, pending, bits)
+    unsigned *pending;
+    int *bits;
+    z_streamp strm;
+{
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    if (pending != Z_NULL)
+        *pending = strm->state->pending;
+    if (bits != Z_NULL)
+        *bits = strm->state->bi_valid;
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflatePrime (strm, bits, value)
+    z_streamp strm;
+    int bits;
+    int value;
+{
+    deflate_state *s;
+    int put;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = strm->state;
+    if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3))
+        return Z_BUF_ERROR;
+    do {
+        put = Buf_size - s->bi_valid;
+        if (put > bits)
+            put = bits;
+        s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid);
+        s->bi_valid += put;
+        _tr_flush_bits(s);
+        value >>= put;
+        bits -= put;
+    } while (bits);
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateParams(strm, level, strategy)
+    z_streamp strm;
+    int level;
+    int strategy;
+{
+    deflate_state *s;
+    compress_func func;
+    int err = Z_OK;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = strm->state;
+
+#ifdef FASTEST
+    if (level != 0) level = 1;
+#else
+    if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) {
+        return Z_STREAM_ERROR;
+    }
+    func = configuration_table[s->level].func;
+
+    if ((strategy != s->strategy || func != configuration_table[level].func) &&
+        strm->total_in != 0) {
+        /* Flush the last buffer: */
+        err = deflate(strm, Z_BLOCK);
+        if (err == Z_BUF_ERROR && s->pending == 0)
+            err = Z_OK;
+    }
+    if (s->level != level) {
+        s->level = level;
+        s->max_lazy_match   = configuration_table[level].max_lazy;
+        s->good_match       = configuration_table[level].good_length;
+        s->nice_match       = configuration_table[level].nice_length;
+        s->max_chain_length = configuration_table[level].max_chain;
+    }
+    s->strategy = strategy;
+    return err;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain)
+    z_streamp strm;
+    int good_length;
+    int max_lazy;
+    int nice_length;
+    int max_chain;
+{
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = strm->state;
+    s->good_match = good_length;
+    s->max_lazy_match = max_lazy;
+    s->nice_match = nice_length;
+    s->max_chain_length = max_chain;
+    return Z_OK;
+}
+
+/* =========================================================================
+ * For the default windowBits of 15 and memLevel of 8, this function returns
+ * a close to exact, as well as small, upper bound on the compressed size.
+ * They are coded as constants here for a reason--if the #define's are
+ * changed, then this function needs to be changed as well.  The return
+ * value for 15 and 8 only works for those exact settings.
+ *
+ * For any setting other than those defaults for windowBits and memLevel,
+ * the value returned is a conservative worst case for the maximum expansion
+ * resulting from using fixed blocks instead of stored blocks, which deflate
+ * can emit on compressed data for some combinations of the parameters.
+ *
+ * This function could be more sophisticated to provide closer upper bounds for
+ * every combination of windowBits and memLevel.  But even the conservative
+ * upper bound of about 14% expansion does not seem onerous for output buffer
+ * allocation.
+ */
+uLong ZEXPORT deflateBound(strm, sourceLen)
+    z_streamp strm;
+    uLong sourceLen;
+{
+    deflate_state *s;
+    uLong complen, wraplen;
+    Bytef *str;
+
+    /* conservative upper bound for compressed data */
+    complen = sourceLen +
+              ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5;
+
+    /* if can't get parameters, return conservative bound plus zlib wrapper */
+    if (strm == Z_NULL || strm->state == Z_NULL)
+        return complen + 6;
+
+    /* compute wrapper length */
+    s = strm->state;
+    switch (s->wrap) {
+    case 0:                                 /* raw deflate */
+        wraplen = 0;
+        break;
+    case 1:                                 /* zlib wrapper */
+        wraplen = 6 + (s->strstart ? 4 : 0);
+        break;
+    case 2:                                 /* gzip wrapper */
+        wraplen = 18;
+        if (s->gzhead != Z_NULL) {          /* user-supplied gzip header */
+            if (s->gzhead->extra != Z_NULL)
+                wraplen += 2 + s->gzhead->extra_len;
+            str = s->gzhead->name;
+            if (str != Z_NULL)
+                do {
+                    wraplen++;
+                } while (*str++);
+            str = s->gzhead->comment;
+            if (str != Z_NULL)
+                do {
+                    wraplen++;
+                } while (*str++);
+            if (s->gzhead->hcrc)
+                wraplen += 2;
+        }
+        break;
+    default:                                /* for compiler happiness */
+        wraplen = 6;
+    }
+
+    /* if not default parameters, return conservative bound */
+    if (s->w_bits != 15 || s->hash_bits != 8 + 7)
+        return complen + wraplen;
+
+    /* default settings: return tight bound for that case */
+    return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
+           (sourceLen >> 25) + 13 - 6 + wraplen;
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+    deflate_state *s;
+    uInt b;
+{
+    put_byte(s, (Byte)(b >> 8));
+    put_byte(s, (Byte)(b & 0xff));
+}
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+    z_streamp strm;
+{
+    unsigned len;
+    deflate_state *s = strm->state;
+
+    _tr_flush_bits(s);
+    len = s->pending;
+    if (len > strm->avail_out) len = strm->avail_out;
+    if (len == 0) return;
+
+    zmemcpy(strm->next_out, s->pending_out, len);
+    strm->next_out  += len;
+    s->pending_out  += len;
+    strm->total_out += len;
+    strm->avail_out  -= len;
+    s->pending -= len;
+    if (s->pending == 0) {
+        s->pending_out = s->pending_buf;
+    }
+}
+
+/* ========================================================================= */
+int ZEXPORT deflate (strm, flush)
+    z_streamp strm;
+    int flush;
+{
+    int old_flush; /* value of flush param for previous deflate call */
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL ||
+        flush > Z_BLOCK || flush < 0) {
+        return Z_STREAM_ERROR;
+    }
+    s = strm->state;
+
+    if (strm->next_out == Z_NULL ||
+        (strm->next_in == Z_NULL && strm->avail_in != 0) ||
+        (s->status == FINISH_STATE && flush != Z_FINISH)) {
+        ERR_RETURN(strm, Z_STREAM_ERROR);
+    }
+    if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+    s->strm = strm; /* just in case */
+    old_flush = s->last_flush;
+    s->last_flush = flush;
+
+    /* Write the header */
+    if (s->status == INIT_STATE) {
+#ifdef GZIP
+        if (s->wrap == 2) {
+            strm->adler = crc32(0L, Z_NULL, 0);
+            put_byte(s, 31);
+            put_byte(s, 139);
+            put_byte(s, 8);
+            if (s->gzhead == Z_NULL) {
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, s->level == 9 ? 2 :
+                            (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+                             4 : 0));
+                put_byte(s, OS_CODE);
+                s->status = BUSY_STATE;
+            }
+            else {
+                put_byte(s, (s->gzhead->text ? 1 : 0) +
+                            (s->gzhead->hcrc ? 2 : 0) +
+                            (s->gzhead->extra == Z_NULL ? 0 : 4) +
+                            (s->gzhead->name == Z_NULL ? 0 : 8) +
+                            (s->gzhead->comment == Z_NULL ? 0 : 16)
+                        );
+                put_byte(s, (Byte)(s->gzhead->time & 0xff));
+                put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff));
+                put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff));
+                put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff));
+                put_byte(s, s->level == 9 ? 2 :
+                            (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+                             4 : 0));
+                put_byte(s, s->gzhead->os & 0xff);
+                if (s->gzhead->extra != Z_NULL) {
+                    put_byte(s, s->gzhead->extra_len & 0xff);
+                    put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);
+                }
+                if (s->gzhead->hcrc)
+                    strm->adler = crc32(strm->adler, s->pending_buf,
+                                        s->pending);
+                s->gzindex = 0;
+                s->status = EXTRA_STATE;
+            }
+        }
+        else
+#endif
+        {
+            uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+            uInt level_flags;
+
+            if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
+                level_flags = 0;
+            else if (s->level < 6)
+                level_flags = 1;
+            else if (s->level == 6)
+                level_flags = 2;
+            else
+                level_flags = 3;
+            header |= (level_flags << 6);
+            if (s->strstart != 0) header |= PRESET_DICT;
+            header += 31 - (header % 31);
+
+            s->status = BUSY_STATE;
+            putShortMSB(s, header);
+
+            /* Save the adler32 of the preset dictionary: */
+            if (s->strstart != 0) {
+                putShortMSB(s, (uInt)(strm->adler >> 16));
+                putShortMSB(s, (uInt)(strm->adler & 0xffff));
+            }
+            strm->adler = adler32(0L, Z_NULL, 0);
+        }
+    }
+#ifdef GZIP
+    if (s->status == EXTRA_STATE) {
+        if (s->gzhead->extra != Z_NULL) {
+            uInt beg = s->pending;  /* start of bytes to update crc */
+
+            while (s->gzindex < (s->gzhead->extra_len & 0xffff)) {
+                if (s->pending == s->pending_buf_size) {
+                    if (s->gzhead->hcrc && s->pending > beg)
+                        strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                            s->pending - beg);
+                    flush_pending(strm);
+                    beg = s->pending;
+                    if (s->pending == s->pending_buf_size)
+                        break;
+                }
+                put_byte(s, s->gzhead->extra[s->gzindex]);
+                s->gzindex++;
+            }
+            if (s->gzhead->hcrc && s->pending > beg)
+                strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                    s->pending - beg);
+            if (s->gzindex == s->gzhead->extra_len) {
+                s->gzindex = 0;
+                s->status = NAME_STATE;
+            }
+        }
+        else
+            s->status = NAME_STATE;
+    }
+    if (s->status == NAME_STATE) {
+        if (s->gzhead->name != Z_NULL) {
+            uInt beg = s->pending;  /* start of bytes to update crc */
+            int val;
+
+            do {
+                if (s->pending == s->pending_buf_size) {
+                    if (s->gzhead->hcrc && s->pending > beg)
+                        strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                            s->pending - beg);
+                    flush_pending(strm);
+                    beg = s->pending;
+                    if (s->pending == s->pending_buf_size) {
+                        val = 1;
+                        break;
+                    }
+                }
+                val = s->gzhead->name[s->gzindex++];
+                put_byte(s, val);
+            } while (val != 0);
+            if (s->gzhead->hcrc && s->pending > beg)
+                strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                    s->pending - beg);
+            if (val == 0) {
+                s->gzindex = 0;
+                s->status = COMMENT_STATE;
+            }
+        }
+        else
+            s->status = COMMENT_STATE;
+    }
+    if (s->status == COMMENT_STATE) {
+        if (s->gzhead->comment != Z_NULL) {
+            uInt beg = s->pending;  /* start of bytes to update crc */
+            int val;
+
+            do {
+                if (s->pending == s->pending_buf_size) {
+                    if (s->gzhead->hcrc && s->pending > beg)
+                        strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                            s->pending - beg);
+                    flush_pending(strm);
+                    beg = s->pending;
+                    if (s->pending == s->pending_buf_size) {
+                        val = 1;
+                        break;
+                    }
+                }
+                val = s->gzhead->comment[s->gzindex++];
+                put_byte(s, val);
+            } while (val != 0);
+            if (s->gzhead->hcrc && s->pending > beg)
+                strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                    s->pending - beg);
+            if (val == 0)
+                s->status = HCRC_STATE;
+        }
+        else
+            s->status = HCRC_STATE;
+    }
+    if (s->status == HCRC_STATE) {
+        if (s->gzhead->hcrc) {
+            if (s->pending + 2 > s->pending_buf_size)
+                flush_pending(strm);
+            if (s->pending + 2 <= s->pending_buf_size) {
+                put_byte(s, (Byte)(strm->adler & 0xff));
+                put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+                strm->adler = crc32(0L, Z_NULL, 0);
+                s->status = BUSY_STATE;
+            }
+        }
+        else
+            s->status = BUSY_STATE;
+    }
+#endif
+
+    /* Flush as much pending output as possible */
+    if (s->pending != 0) {
+        flush_pending(strm);
+        if (strm->avail_out == 0) {
+            /* Since avail_out is 0, deflate will be called again with
+             * more output space, but possibly with both pending and
+             * avail_in equal to zero. There won't be anything to do,
+             * but this is not an error situation so make sure we
+             * return OK instead of BUF_ERROR at next call of deflate:
+             */
+            s->last_flush = -1;
+            return Z_OK;
+        }
+
+    /* Make sure there is something to do and avoid duplicate consecutive
+     * flushes. For repeated and useless calls with Z_FINISH, we keep
+     * returning Z_STREAM_END instead of Z_BUF_ERROR.
+     */
+    } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) &&
+               flush != Z_FINISH) {
+        ERR_RETURN(strm, Z_BUF_ERROR);
+    }
+
+    /* User must not provide more input after the first FINISH: */
+    if (s->status == FINISH_STATE && strm->avail_in != 0) {
+        ERR_RETURN(strm, Z_BUF_ERROR);
+    }
+
+    /* Start a new block or continue the current one.
+     */
+    if (strm->avail_in != 0 || s->lookahead != 0 ||
+        (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+        block_state bstate;
+
+        bstate = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) :
+                    (s->strategy == Z_RLE ? deflate_rle(s, flush) :
+                        (*(configuration_table[s->level].func))(s, flush));
+
+        if (bstate == finish_started || bstate == finish_done) {
+            s->status = FINISH_STATE;
+        }
+        if (bstate == need_more || bstate == finish_started) {
+            if (strm->avail_out == 0) {
+                s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+            }
+            return Z_OK;
+            /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+             * of deflate should use the same flush parameter to make sure
+             * that the flush is complete. So we don't have to output an
+             * empty block here, this will be done at next call. This also
+             * ensures that for a very small output buffer, we emit at most
+             * one empty block.
+             */
+        }
+        if (bstate == block_done) {
+            if (flush == Z_PARTIAL_FLUSH) {
+                _tr_align(s);
+            } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */
+                _tr_stored_block(s, (char*)0, 0L, 0);
+                /* For a full flush, this empty block will be recognized
+                 * as a special marker by inflate_sync().
+                 */
+                if (flush == Z_FULL_FLUSH) {
+                    CLEAR_HASH(s);             /* forget history */
+                    if (s->lookahead == 0) {
+                        s->strstart = 0;
+                        s->block_start = 0L;
+                        s->insert = 0;
+                    }
+                }
+            }
+            flush_pending(strm);
+            if (strm->avail_out == 0) {
+              s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+              return Z_OK;
+            }
+        }
+    }
+    Assert(strm->avail_out > 0, "bug2");
+
+    if (flush != Z_FINISH) return Z_OK;
+    if (s->wrap <= 0) return Z_STREAM_END;
+
+    /* Write the trailer */
+#ifdef GZIP
+    if (s->wrap == 2) {
+        put_byte(s, (Byte)(strm->adler & 0xff));
+        put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+        put_byte(s, (Byte)((strm->adler >> 16) & 0xff));
+        put_byte(s, (Byte)((strm->adler >> 24) & 0xff));
+        put_byte(s, (Byte)(strm->total_in & 0xff));
+        put_byte(s, (Byte)((strm->total_in >> 8) & 0xff));
+        put_byte(s, (Byte)((strm->total_in >> 16) & 0xff));
+        put_byte(s, (Byte)((strm->total_in >> 24) & 0xff));
+    }
+    else
+#endif
+    {
+        putShortMSB(s, (uInt)(strm->adler >> 16));
+        putShortMSB(s, (uInt)(strm->adler & 0xffff));
+    }
+    flush_pending(strm);
+    /* If avail_out is zero, the application will call deflate again
+     * to flush the rest.
+     */
+    if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */
+    return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateEnd (strm)
+    z_streamp strm;
+{
+    int status;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+
+    status = strm->state->status;
+    if (status != INIT_STATE &&
+        status != EXTRA_STATE &&
+        status != NAME_STATE &&
+        status != COMMENT_STATE &&
+        status != HCRC_STATE &&
+        status != BUSY_STATE &&
+        status != FINISH_STATE) {
+      return Z_STREAM_ERROR;
+    }
+
+    /* Deallocate in reverse order of allocations: */
+    TRY_FREE(strm, strm->state->pending_buf);
+    TRY_FREE(strm, strm->state->head);
+    TRY_FREE(strm, strm->state->prev);
+    TRY_FREE(strm, strm->state->window);
+
+    ZFREE(strm, strm->state);
+    strm->state = Z_NULL;
+
+    return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ * To simplify the source, this is not supported for 16-bit MSDOS (which
+ * doesn't have enough memory anyway to duplicate compression states).
+ */
+int ZEXPORT deflateCopy (dest, source)
+    z_streamp dest;
+    z_streamp source;
+{
+#ifdef MAXSEG_64K
+    return Z_STREAM_ERROR;
+#else
+    deflate_state *ds;
+    deflate_state *ss;
+    ushf *overlay;
+
+
+    if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
+        return Z_STREAM_ERROR;
+    }
+
+    ss = source->state;
+
+    zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));
+
+    ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+    if (ds == Z_NULL) return Z_MEM_ERROR;
+    dest->state = (struct internal_state FAR *) ds;
+    zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state));
+    ds->strm = dest;
+
+    ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+    ds->prev   = (Posf *)  ZALLOC(dest, ds->w_size, sizeof(Pos));
+    ds->head   = (Posf *)  ZALLOC(dest, ds->hash_size, sizeof(Pos));
+    overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+    ds->pending_buf = (uchf *) overlay;
+
+    if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+        ds->pending_buf == Z_NULL) {
+        deflateEnd (dest);
+        return Z_MEM_ERROR;
+    }
+    /* following zmemcpy do not work for 16-bit MSDOS */
+    zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+    zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos));
+    zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos));
+    zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+    ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+    ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+    ds->l_desc.dyn_tree = ds->dyn_ltree;
+    ds->d_desc.dyn_tree = ds->dyn_dtree;
+    ds->bl_desc.dyn_tree = ds->bl_tree;
+
+    return Z_OK;
+#endif /* MAXSEG_64K */
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read.  All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+    z_streamp strm;
+    Bytef *buf;
+    unsigned size;
+{
+    unsigned len = strm->avail_in;
+
+    if (len > size) len = size;
+    if (len == 0) return 0;
+
+    strm->avail_in  -= len;
+
+    zmemcpy(buf, strm->next_in, len);
+    if (strm->state->wrap == 1) {
+        strm->adler = adler32(strm->adler, buf, len);
+    }
+#ifdef GZIP
+    else if (strm->state->wrap == 2) {
+        strm->adler = crc32(strm->adler, buf, len);
+    }
+#endif
+    strm->next_in  += len;
+    strm->total_in += len;
+
+    return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+    deflate_state *s;
+{
+    s->window_size = (ulg)2L*s->w_size;
+
+    CLEAR_HASH(s);
+
+    /* Set the default configuration parameters:
+     */
+    s->max_lazy_match   = configuration_table[s->level].max_lazy;
+    s->good_match       = configuration_table[s->level].good_length;
+    s->nice_match       = configuration_table[s->level].nice_length;
+    s->max_chain_length = configuration_table[s->level].max_chain;
+
+    s->strstart = 0;
+    s->block_start = 0L;
+    s->lookahead = 0;
+    s->insert = 0;
+    s->match_length = s->prev_length = MIN_MATCH-1;
+    s->match_available = 0;
+    s->ins_h = 0;
+#ifndef FASTEST
+#ifdef ASMV
+    match_init(); /* initialize the asm code */
+#endif
+#endif
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(s, cur_match)
+    deflate_state *s;
+    IPos cur_match;                             /* current match */
+{
+    unsigned chain_length = s->max_chain_length;/* max hash chain length */
+    register Bytef *scan = s->window + s->strstart; /* current string */
+    register Bytef *match;                       /* matched string */
+    register int len;                           /* length of current match */
+    int best_len = s->prev_length;              /* best match length so far */
+    int nice_match = s->nice_match;             /* stop if match long enough */
+    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+        s->strstart - (IPos)MAX_DIST(s) : NIL;
+    /* Stop when cur_match becomes <= limit. To simplify the code,
+     * we prevent matches with the string of window index 0.
+     */
+    Posf *prev = s->prev;
+    uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+    /* Compare two bytes at a time. Note: this is not always beneficial.
+     * Try with and without -DUNALIGNED_OK to check.
+     */
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+    register ush scan_start = *(ushf*)scan;
+    register ush scan_end   = *(ushf*)(scan+best_len-1);
+#else
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+    register Byte scan_end1  = scan[best_len-1];
+    register Byte scan_end   = scan[best_len];
+#endif
+
+    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+     * It is easy to get rid of this optimization if necessary.
+     */
+    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+    /* Do not waste too much time if we already have a good match: */
+    if (s->prev_length >= s->good_match) {
+        chain_length >>= 2;
+    }
+    /* Do not look for matches beyond the end of the input. This is necessary
+     * to make deflate deterministic.
+     */
+    if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+    do {
+        Assert(cur_match < s->strstart, "no future");
+        match = s->window + cur_match;
+
+        /* Skip to next match if the match length cannot increase
+         * or if the match length is less than 2.  Note that the checks below
+         * for insufficient lookahead only occur occasionally for performance
+         * reasons.  Therefore uninitialized memory will be accessed, and
+         * conditional jumps will be made that depend on those values.
+         * However the length of the match is limited to the lookahead, so
+         * the output of deflate is not affected by the uninitialized values.
+         */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+        /* This code assumes sizeof(unsigned short) == 2. Do not use
+         * UNALIGNED_OK if your compiler uses a different size.
+         */
+        if (*(ushf*)(match+best_len-1) != scan_end ||
+            *(ushf*)match != scan_start) continue;
+
+        /* It is not necessary to compare scan[2] and match[2] since they are
+         * always equal when the other bytes match, given that the hash keys
+         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+         * strstart+3, +5, ... up to strstart+257. We check for insufficient
+         * lookahead only every 4th comparison; the 128th check will be made
+         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+         * necessary to put more guard bytes at the end of the window, or
+         * to check more often for insufficient lookahead.
+         */
+        Assert(scan[2] == match[2], "scan[2]?");
+        scan++, match++;
+        do {
+        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 scan < strend);
+        /* The funny "do {}" generates better code on most compilers */
+
+        /* Here, scan <= window+strstart+257 */
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+        if (*scan == *match) scan++;
+
+        len = (MAX_MATCH - 1) - (int)(strend-scan);
+        scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+        if (match[best_len]   != scan_end  ||
+            match[best_len-1] != scan_end1 ||
+            *match            != *scan     ||
+            *++match          != scan[1])      continue;
+
+        /* The check at best_len-1 can be removed because it will be made
+         * again later. (This heuristic is not always a win.)
+         * It is not necessary to compare scan[2] and match[2] since they
+         * are always equal when the other bytes match, given that
+         * the hash keys are equal and that HASH_BITS >= 8.
+         */
+        scan += 2, match++;
+        Assert(*scan == *match, "match[2]?");
+
+        /* We check for insufficient lookahead only every 8th comparison;
+         * the 256th check will be made at strstart+258.
+         */
+        do {
+        } while (*++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 scan < strend);
+
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+        len = MAX_MATCH - (int)(strend - scan);
+        scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+        if (len > best_len) {
+            s->match_start = cur_match;
+            best_len = len;
+            if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+            scan_end = *(ushf*)(scan+best_len-1);
+#else
+            scan_end1  = scan[best_len-1];
+            scan_end   = scan[best_len];
+#endif
+        }
+    } while ((cur_match = prev[cur_match & wmask]) > limit
+             && --chain_length != 0);
+
+    if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+    return s->lookahead;
+}
+#endif /* ASMV */
+
+#else /* FASTEST */
+
+/* ---------------------------------------------------------------------------
+ * Optimized version for FASTEST only
+ */
+local uInt longest_match(s, cur_match)
+    deflate_state *s;
+    IPos cur_match;                             /* current match */
+{
+    register Bytef *scan = s->window + s->strstart; /* current string */
+    register Bytef *match;                       /* matched string */
+    register int len;                           /* length of current match */
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+
+    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+     * It is easy to get rid of this optimization if necessary.
+     */
+    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+    Assert(cur_match < s->strstart, "no future");
+
+    match = s->window + cur_match;
+
+    /* Return failure if the match length is less than 2:
+     */
+    if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
+
+    /* The check at best_len-1 can be removed because it will be made
+     * again later. (This heuristic is not always a win.)
+     * It is not necessary to compare scan[2] and match[2] since they
+     * are always equal when the other bytes match, given that
+     * the hash keys are equal and that HASH_BITS >= 8.
+     */
+    scan += 2, match += 2;
+    Assert(*scan == *match, "match[2]?");
+
+    /* We check for insufficient lookahead only every 8th comparison;
+     * the 256th check will be made at strstart+258.
+     */
+    do {
+    } while (*++scan == *++match && *++scan == *++match &&
+             *++scan == *++match && *++scan == *++match &&
+             *++scan == *++match && *++scan == *++match &&
+             *++scan == *++match && *++scan == *++match &&
+             scan < strend);
+
+    Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+    len = MAX_MATCH - (int)(strend - scan);
+
+    if (len < MIN_MATCH) return MIN_MATCH - 1;
+
+    s->match_start = cur_match;
+    return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead;
+}
+
+#endif /* FASTEST */
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+    deflate_state *s;
+    IPos start, match;
+    int length;
+{
+    /* check that the match is indeed a match */
+    if (zmemcmp(s->window + match,
+                s->window + start, length) != EQUAL) {
+        fprintf(stderr, " start %u, match %u, length %d\n",
+                start, match, length);
+        do {
+            fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+        } while (--length != 0);
+        z_error("invalid match");
+    }
+    if (z_verbose > 1) {
+        fprintf(stderr,"\\[%d,%d]", start-match, length);
+        do { putc(s->window[start++], stderr); } while (--length != 0);
+    }
+}
+#else
+#  define check_match(s, start, match, length)
+#endif /* DEBUG */
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ *    At least one byte has been read, or avail_in == 0; reads are
+ *    performed for at least two bytes (required for the zip translate_eol
+ *    option -- not supported here).
+ */
+local void fill_window(s)
+    deflate_state *s;
+{
+    register unsigned n, m;
+    register Posf *p;
+    unsigned more;    /* Amount of free space at the end of the window. */
+    uInt wsize = s->w_size;
+
+    Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead");
+
+    do {
+        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+        /* Deal with !@#$% 64K limit: */
+        if (sizeof(int) <= 2) {
+            if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+                more = wsize;
+
+            } else if (more == (unsigned)(-1)) {
+                /* Very unlikely, but possible on 16 bit machine if
+                 * strstart == 0 && lookahead == 1 (input done a byte at time)
+                 */
+                more--;
+            }
+        }
+
+        /* If the window is almost full and there is insufficient lookahead,
+         * move the upper half to the lower one to make room in the upper half.
+         */
+        if (s->strstart >= wsize+MAX_DIST(s)) {
+
+            zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
+            s->match_start -= wsize;
+            s->strstart    -= wsize; /* we now have strstart >= MAX_DIST */
+            s->block_start -= (long) wsize;
+
+            /* Slide the hash table (could be avoided with 32 bit values
+               at the expense of memory usage). We slide even when level == 0
+               to keep the hash table consistent if we switch back to level > 0
+               later. (Using level 0 permanently is not an optimal usage of
+               zlib, so we don't care about this pathological case.)
+             */
+            n = s->hash_size;
+            p = &s->head[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= wsize ? m-wsize : NIL);
+            } while (--n);
+
+            n = wsize;
+#ifndef FASTEST
+            p = &s->prev[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= wsize ? m-wsize : NIL);
+                /* If n is not on any hash chain, prev[n] is garbage but
+                 * its value will never be used.
+                 */
+            } while (--n);
+#endif
+            more += wsize;
+        }
+        if (s->strm->avail_in == 0) break;
+
+        /* If there was no sliding:
+         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+         *    more == window_size - lookahead - strstart
+         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+         * => more >= window_size - 2*WSIZE + 2
+         * In the BIG_MEM or MMAP case (not yet supported),
+         *   window_size == input_size + MIN_LOOKAHEAD  &&
+         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+         * Otherwise, window_size == 2*WSIZE so more >= 2.
+         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+         */
+        Assert(more >= 2, "more < 2");
+
+        n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+        s->lookahead += n;
+
+        /* Initialize the hash value now that we have some input: */
+        if (s->lookahead + s->insert >= MIN_MATCH) {
+            uInt str = s->strstart - s->insert;
+            s->ins_h = s->window[str];
+            UPDATE_HASH(s, s->ins_h, s->window[str + 1]);
+#if MIN_MATCH != 3
+            Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+            while (s->insert) {
+                UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);
+#ifndef FASTEST
+                s->prev[str & s->w_mask] = s->head[s->ins_h];
+#endif
+                s->head[s->ins_h] = (Pos)str;
+                str++;
+                s->insert--;
+                if (s->lookahead + s->insert < MIN_MATCH)
+                    break;
+            }
+        }
+        /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+         * but this is not important since only literal bytes will be emitted.
+         */
+
+    } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+
+    /* If the WIN_INIT bytes after the end of the current data have never been
+     * written, then zero those bytes in order to avoid memory check reports of
+     * the use of uninitialized (or uninitialised as Julian writes) bytes by
+     * the longest match routines.  Update the high water mark for the next
+     * time through here.  WIN_INIT is set to MAX_MATCH since the longest match
+     * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.
+     */
+    if (s->high_water < s->window_size) {
+        ulg curr = s->strstart + (ulg)(s->lookahead);
+        ulg init;
+
+        if (s->high_water < curr) {
+            /* Previous high water mark below current data -- zero WIN_INIT
+             * bytes or up to end of window, whichever is less.
+             */
+            init = s->window_size - curr;
+            if (init > WIN_INIT)
+                init = WIN_INIT;
+            zmemzero(s->window + curr, (unsigned)init);
+            s->high_water = curr + init;
+        }
+        else if (s->high_water < (ulg)curr + WIN_INIT) {
+            /* High water mark at or above current data, but below current data
+             * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up
+             * to end of window, whichever is less.
+             */
+            init = (ulg)curr + WIN_INIT - s->high_water;
+            if (init > s->window_size - s->high_water)
+                init = s->window_size - s->high_water;
+            zmemzero(s->window + s->high_water, (unsigned)init);
+            s->high_water += init;
+        }
+    }
+
+    Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
+           "not enough room for search");
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, last) { \
+   _tr_flush_block(s, (s->block_start >= 0L ? \
+                   (charf *)&s->window[(unsigned)s->block_start] : \
+                   (charf *)Z_NULL), \
+                (ulg)((long)s->strstart - s->block_start), \
+                (last)); \
+   s->block_start = s->strstart; \
+   flush_pending(s->strm); \
+   Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, last) { \
+   FLUSH_BLOCK_ONLY(s, last); \
+   if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+     * to pending_buf_size, and each stored block has a 5 byte header:
+     */
+    ulg max_block_size = 0xffff;
+    ulg max_start;
+
+    if (max_block_size > s->pending_buf_size - 5) {
+        max_block_size = s->pending_buf_size - 5;
+    }
+
+    /* Copy as much as possible from input to output: */
+    for (;;) {
+        /* Fill the window as much as possible: */
+        if (s->lookahead <= 1) {
+
+            Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+                   s->block_start >= (long)s->w_size, "slide too late");
+
+            fill_window(s);
+            if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+        Assert(s->block_start >= 0L, "block gone");
+
+        s->strstart += s->lookahead;
+        s->lookahead = 0;
+
+        /* Emit a stored block if pending_buf will be full: */
+        max_start = s->block_start + max_block_size;
+        if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+            /* strstart == 0 is possible when wraparound on 16-bit machine */
+            s->lookahead = (uInt)(s->strstart - max_start);
+            s->strstart = (uInt)max_start;
+            FLUSH_BLOCK(s, 0);
+        }
+        /* Flush if we may have to slide, otherwise block_start may become
+         * negative and the data will be gone:
+         */
+        if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+            FLUSH_BLOCK(s, 0);
+        }
+    }
+    s->insert = 0;
+    if (flush == Z_FINISH) {
+        FLUSH_BLOCK(s, 1);
+        return finish_done;
+    }
+    if ((long)s->strstart > s->block_start)
+        FLUSH_BLOCK(s, 0);
+    return block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head;       /* head of the hash chain */
+    int bflush;           /* set if current block must be flushed */
+
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+                return need_more;
+            }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        hash_head = NIL;
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         * At this point we have always match_length < MIN_MATCH
+         */
+        if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            s->match_length = longest_match (s, hash_head);
+            /* longest_match() sets match_start */
+        }
+        if (s->match_length >= MIN_MATCH) {
+            check_match(s, s->strstart, s->match_start, s->match_length);
+
+            _tr_tally_dist(s, s->strstart - s->match_start,
+                           s->match_length - MIN_MATCH, bflush);
+
+            s->lookahead -= s->match_length;
+
+            /* Insert new strings in the hash table only if the match length
+             * is not too large. This saves time but degrades compression.
+             */
+#ifndef FASTEST
+            if (s->match_length <= s->max_insert_length &&
+                s->lookahead >= MIN_MATCH) {
+                s->match_length--; /* string at strstart already in table */
+                do {
+                    s->strstart++;
+                    INSERT_STRING(s, s->strstart, hash_head);
+                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+                     * always MIN_MATCH bytes ahead.
+                     */
+                } while (--s->match_length != 0);
+                s->strstart++;
+            } else
+#endif
+            {
+                s->strstart += s->match_length;
+                s->match_length = 0;
+                s->ins_h = s->window[s->strstart];
+                UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+                Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+                /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+                 * matter since it will be recomputed at next deflate call.
+                 */
+            }
+        } else {
+            /* No match, output a literal byte */
+            Tracevv((stderr,"%c", s->window[s->strstart]));
+            _tr_tally_lit (s, s->window[s->strstart], bflush);
+            s->lookahead--;
+            s->strstart++;
+        }
+        if (bflush) FLUSH_BLOCK(s, 0);
+    }
+    s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1;
+    if (flush == Z_FINISH) {
+        FLUSH_BLOCK(s, 1);
+        return finish_done;
+    }
+    if (s->last_lit)
+        FLUSH_BLOCK(s, 0);
+    return block_done;
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head;          /* head of hash chain */
+    int bflush;              /* set if current block must be flushed */
+
+    /* Process the input block. */
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+                return need_more;
+            }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        hash_head = NIL;
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         */
+        s->prev_length = s->match_length, s->prev_match = s->match_start;
+        s->match_length = MIN_MATCH-1;
+
+        if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+            s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            s->match_length = longest_match (s, hash_head);
+            /* longest_match() sets match_start */
+
+            if (s->match_length <= 5 && (s->strategy == Z_FILTERED
+#if TOO_FAR <= 32767
+                || (s->match_length == MIN_MATCH &&
+                    s->strstart - s->match_start > TOO_FAR)
+#endif
+                )) {
+
+                /* If prev_match is also MIN_MATCH, match_start is garbage
+                 * but we will ignore the current match anyway.
+                 */
+                s->match_length = MIN_MATCH-1;
+            }
+        }
+        /* If there was a match at the previous step and the current
+         * match is not better, output the previous match:
+         */
+        if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+            uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+            /* Do not insert strings in hash table beyond this. */
+
+            check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+            _tr_tally_dist(s, s->strstart -1 - s->prev_match,
+                           s->prev_length - MIN_MATCH, bflush);
+
+            /* Insert in hash table all strings up to the end of the match.
+             * strstart-1 and strstart are already inserted. If there is not
+             * enough lookahead, the last two strings are not inserted in
+             * the hash table.
+             */
+            s->lookahead -= s->prev_length-1;
+            s->prev_length -= 2;
+            do {
+                if (++s->strstart <= max_insert) {
+                    INSERT_STRING(s, s->strstart, hash_head);
+                }
+            } while (--s->prev_length != 0);
+            s->match_available = 0;
+            s->match_length = MIN_MATCH-1;
+            s->strstart++;
+
+            if (bflush) FLUSH_BLOCK(s, 0);
+
+        } else if (s->match_available) {
+            /* If there was no match at the previous position, output a
+             * single literal. If there was a match but the current match
+             * is longer, truncate the previous match to a single literal.
+             */
+            Tracevv((stderr,"%c", s->window[s->strstart-1]));
+            _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+            if (bflush) {
+                FLUSH_BLOCK_ONLY(s, 0);
+            }
+            s->strstart++;
+            s->lookahead--;
+            if (s->strm->avail_out == 0) return need_more;
+        } else {
+            /* There is no previous match to compare with, wait for
+             * the next step to decide.
+             */
+            s->match_available = 1;
+            s->strstart++;
+            s->lookahead--;
+        }
+    }
+    Assert (flush != Z_NO_FLUSH, "no flush?");
+    if (s->match_available) {
+        Tracevv((stderr,"%c", s->window[s->strstart-1]));
+        _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+        s->match_available = 0;
+    }
+    s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1;
+    if (flush == Z_FINISH) {
+        FLUSH_BLOCK(s, 1);
+        return finish_done;
+    }
+    if (s->last_lit)
+        FLUSH_BLOCK(s, 0);
+    return block_done;
+}
+#endif /* FASTEST */
+
+/* ===========================================================================
+ * For Z_RLE, simply look for runs of bytes, generate matches only of distance
+ * one.  Do not maintain a hash table.  (It will be regenerated if this run of
+ * deflate switches away from Z_RLE.)
+ */
+local block_state deflate_rle(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    int bflush;             /* set if current block must be flushed */
+    uInt prev;              /* byte at distance one to match */
+    Bytef *scan, *strend;   /* scan goes up to strend for length of run */
+
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the longest run, plus one for the unrolled loop.
+         */
+        if (s->lookahead <= MAX_MATCH) {
+            fill_window(s);
+            if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) {
+                return need_more;
+            }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* See how many times the previous byte repeats */
+        s->match_length = 0;
+        if (s->lookahead >= MIN_MATCH && s->strstart > 0) {
+            scan = s->window + s->strstart - 1;
+            prev = *scan;
+            if (prev == *++scan && prev == *++scan && prev == *++scan) {
+                strend = s->window + s->strstart + MAX_MATCH;
+                do {
+                } while (prev == *++scan && prev == *++scan &&
+                         prev == *++scan && prev == *++scan &&
+                         prev == *++scan && prev == *++scan &&
+                         prev == *++scan && prev == *++scan &&
+                         scan < strend);
+                s->match_length = MAX_MATCH - (int)(strend - scan);
+                if (s->match_length > s->lookahead)
+                    s->match_length = s->lookahead;
+            }
+            Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan");
+        }
+
+        /* Emit match if have run of MIN_MATCH or longer, else emit literal */
+        if (s->match_length >= MIN_MATCH) {
+            check_match(s, s->strstart, s->strstart - 1, s->match_length);
+
+            _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush);
+
+            s->lookahead -= s->match_length;
+            s->strstart += s->match_length;
+            s->match_length = 0;
+        } else {
+            /* No match, output a literal byte */
+            Tracevv((stderr,"%c", s->window[s->strstart]));
+            _tr_tally_lit (s, s->window[s->strstart], bflush);
+            s->lookahead--;
+            s->strstart++;
+        }
+        if (bflush) FLUSH_BLOCK(s, 0);
+    }
+    s->insert = 0;
+    if (flush == Z_FINISH) {
+        FLUSH_BLOCK(s, 1);
+        return finish_done;
+    }
+    if (s->last_lit)
+        FLUSH_BLOCK(s, 0);
+    return block_done;
+}
+
+/* ===========================================================================
+ * For Z_HUFFMAN_ONLY, do not look for matches.  Do not maintain a hash table.
+ * (It will be regenerated if this run of deflate switches away from Huffman.)
+ */
+local block_state deflate_huff(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    int bflush;             /* set if current block must be flushed */
+
+    for (;;) {
+        /* Make sure that we have a literal to write. */
+        if (s->lookahead == 0) {
+            fill_window(s);
+            if (s->lookahead == 0) {
+                if (flush == Z_NO_FLUSH)
+                    return need_more;
+                break;      /* flush the current block */
+            }
+        }
+
+        /* Output a literal byte */
+        s->match_length = 0;
+        Tracevv((stderr,"%c", s->window[s->strstart]));
+        _tr_tally_lit (s, s->window[s->strstart], bflush);
+        s->lookahead--;
+        s->strstart++;
+        if (bflush) FLUSH_BLOCK(s, 0);
+    }
+    s->insert = 0;
+    if (flush == Z_FINISH) {
+        FLUSH_BLOCK(s, 1);
+        return finish_done;
+    }
+    if (s->last_lit)
+        FLUSH_BLOCK(s, 0);
+    return block_done;
+}
diff --git a/src/external/tng_io/external/zlib/deflate.h b/src/external/tng_io/external/zlib/deflate.h
new file mode 100644 (file)
index 0000000..ce0299e
--- /dev/null
@@ -0,0 +1,346 @@
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-2012 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef DEFLATE_H
+#define DEFLATE_H
+
+#include "zutil.h"
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+   trailer creation by deflate().  NO_GZIP would be used to avoid linking in
+   the crc code when it is not needed.  For shared libraries, gzip encoding
+   should be left enabled. */
+#ifndef NO_GZIP
+#  define GZIP
+#endif
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS  256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES   30
+/* number of distance codes */
+
+#define BL_CODES  19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define Buf_size 16
+/* size of bit buffer in bi_buf */
+
+#define INIT_STATE    42
+#define EXTRA_STATE   69
+#define NAME_STATE    73
+#define COMMENT_STATE 91
+#define HCRC_STATE   103
+#define BUSY_STATE   113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+    union {
+        ush  freq;       /* frequency count */
+        ush  code;       /* bit string */
+    } fc;
+    union {
+        ush  dad;        /* father node in Huffman tree */
+        ush  len;        /* length of bit string */
+    } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad  dl.dad
+#define Len  dl.len
+
+typedef struct static_tree_desc_s  static_tree_desc;
+
+typedef struct tree_desc_s {
+    ct_data *dyn_tree;           /* the dynamic tree */
+    int     max_code;            /* largest code with non zero frequency */
+    static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct internal_state {
+    z_streamp strm;      /* pointer back to this zlib stream */
+    int   status;        /* as the name implies */
+    Bytef *pending_buf;  /* output still pending */
+    ulg   pending_buf_size; /* size of pending_buf */
+    Bytef *pending_out;  /* next pending byte to output to the stream */
+    uInt   pending;      /* nb of bytes in the pending buffer */
+    int   wrap;          /* bit 0 true for zlib, bit 1 true for gzip */
+    gz_headerp  gzhead;  /* gzip header information to write */
+    uInt   gzindex;      /* where in extra, name, or comment */
+    Byte  method;        /* can only be DEFLATED */
+    int   last_flush;    /* value of flush param for previous deflate call */
+
+                /* used by deflate.c: */
+
+    uInt  w_size;        /* LZ77 window size (32K by default) */
+    uInt  w_bits;        /* log2(w_size)  (8..16) */
+    uInt  w_mask;        /* w_size - 1 */
+
+    Bytef *window;
+    /* Sliding window. Input bytes are read into the second half of the window,
+     * and move to the first half later to keep a dictionary of at least wSize
+     * bytes. With this organization, matches are limited to a distance of
+     * wSize-MAX_MATCH bytes, but this ensures that IO is always
+     * performed with a length multiple of the block size. Also, it limits
+     * the window size to 64K, which is quite useful on MSDOS.
+     * To do: use the user input buffer as sliding window.
+     */
+
+    ulg window_size;
+    /* Actual size of window: 2*wSize, except when the user input buffer
+     * is directly used as sliding window.
+     */
+
+    Posf *prev;
+    /* Link to older string with same hash index. To limit the size of this
+     * array to 64K, this link is maintained only for the last 32K strings.
+     * An index in this array is thus a window index modulo 32K.
+     */
+
+    Posf *head; /* Heads of the hash chains or NIL. */
+
+    uInt  ins_h;          /* hash index of string to be inserted */
+    uInt  hash_size;      /* number of elements in hash table */
+    uInt  hash_bits;      /* log2(hash_size) */
+    uInt  hash_mask;      /* hash_size-1 */
+
+    uInt  hash_shift;
+    /* Number of bits by which ins_h must be shifted at each input
+     * step. It must be such that after MIN_MATCH steps, the oldest
+     * byte no longer takes part in the hash key, that is:
+     *   hash_shift * MIN_MATCH >= hash_bits
+     */
+
+    long block_start;
+    /* Window position at the beginning of the current output block. Gets
+     * negative when the window is moved backwards.
+     */
+
+    uInt match_length;           /* length of best match */
+    IPos prev_match;             /* previous match */
+    int match_available;         /* set if previous match exists */
+    uInt strstart;               /* start of string to insert */
+    uInt match_start;            /* start of matching string */
+    uInt lookahead;              /* number of valid bytes ahead in window */
+
+    uInt prev_length;
+    /* Length of the best match at previous step. Matches not greater than this
+     * are discarded. This is used in the lazy match evaluation.
+     */
+
+    uInt max_chain_length;
+    /* To speed up deflation, hash chains are never searched beyond this
+     * length.  A higher limit improves compression ratio but degrades the
+     * speed.
+     */
+
+    uInt max_lazy_match;
+    /* Attempt to find a better match only when the current match is strictly
+     * smaller than this value. This mechanism is used only for compression
+     * levels >= 4.
+     */
+#   define max_insert_length  max_lazy_match
+    /* Insert new strings in the hash table only if the match length is not
+     * greater than this length. This saves time but degrades compression.
+     * max_insert_length is used only for compression levels <= 3.
+     */
+
+    int level;    /* compression level (1..9) */
+    int strategy; /* favor or force Huffman coding*/
+
+    uInt good_match;
+    /* Use a faster search when the previous match is longer than this */
+
+    int nice_match; /* Stop searching when current match exceeds this */
+
+                /* used by trees.c: */
+    /* Didn't use ct_data typedef below to suppress compiler warning */
+    struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
+    struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+    struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
+
+    struct tree_desc_s l_desc;               /* desc. for literal tree */
+    struct tree_desc_s d_desc;               /* desc. for distance tree */
+    struct tree_desc_s bl_desc;              /* desc. for bit length tree */
+
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
+    int heap_len;               /* number of elements in the heap */
+    int heap_max;               /* element of largest frequency */
+    /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+     * The same heap array is used to build all trees.
+     */
+
+    uch depth[2*L_CODES+1];
+    /* Depth of each subtree used as tie breaker for trees of equal frequency
+     */
+
+    uchf *l_buf;          /* buffer for literals or lengths */
+
+    uInt  lit_bufsize;
+    /* Size of match buffer for literals/lengths.  There are 4 reasons for
+     * limiting lit_bufsize to 64K:
+     *   - frequencies can be kept in 16 bit counters
+     *   - if compression is not successful for the first block, all input
+     *     data is still in the window so we can still emit a stored block even
+     *     when input comes from standard input.  (This can also be done for
+     *     all blocks if lit_bufsize is not greater than 32K.)
+     *   - if compression is not successful for a file smaller than 64K, we can
+     *     even emit a stored file instead of a stored block (saving 5 bytes).
+     *     This is applicable only for zip (not gzip or zlib).
+     *   - creating new Huffman trees less frequently may not provide fast
+     *     adaptation to changes in the input data statistics. (Take for
+     *     example a binary file with poorly compressible code followed by
+     *     a highly compressible string table.) Smaller buffer sizes give
+     *     fast adaptation but have of course the overhead of transmitting
+     *     trees more frequently.
+     *   - I can't count above 4
+     */
+
+    uInt last_lit;      /* running index in l_buf */
+
+    ushf *d_buf;
+    /* Buffer for distances. To simplify the code, d_buf and l_buf have
+     * the same number of elements. To use different lengths, an extra flag
+     * array would be necessary.
+     */
+
+    ulg opt_len;        /* bit length of current block with optimal trees */
+    ulg static_len;     /* bit length of current block with static trees */
+    uInt matches;       /* number of string matches in current block */
+    uInt insert;        /* bytes at end of window left to insert */
+
+#ifdef DEBUG
+    ulg compressed_len; /* total bit length of compressed file mod 2^32 */
+    ulg bits_sent;      /* bit length of compressed data sent mod 2^32 */
+#endif
+
+    ush bi_buf;
+    /* Output buffer. bits are inserted starting at the bottom (least
+     * significant bits).
+     */
+    int bi_valid;
+    /* Number of valid bits in bi_buf.  All bits above the last valid bit
+     * are always zero.
+     */
+
+    ulg high_water;
+    /* High water mark offset in window for initialized bytes -- bytes above
+     * this are set to zero in order to avoid memory check warnings when
+     * longest match routines access bytes past the input.  This is then
+     * updated to the new high water mark.
+     */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s)  ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+#define WIN_INIT MAX_MATCH
+/* Number of bytes after end of data in window to initialize in order to avoid
+   memory checker errors from longest match routines */
+
+        /* in trees.c */
+void ZLIB_INTERNAL _tr_init OF((deflate_state *s));
+int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
+void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf,
+                        ulg stored_len, int last));
+void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s));
+void ZLIB_INTERNAL _tr_align OF((deflate_state *s));
+void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
+                        ulg stored_len, int last));
+
+#define d_code(dist) \
+   ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. _dist_code[256] and _dist_code[257] are never
+ * used.
+ */
+
+#ifndef DEBUG
+/* Inline versions of _tr_tally for speed: */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+  extern uch ZLIB_INTERNAL _length_code[];
+  extern uch ZLIB_INTERNAL _dist_code[];
+#else
+  extern const uch ZLIB_INTERNAL _length_code[];
+  extern const uch ZLIB_INTERNAL _dist_code[];
+#endif
+
+# define _tr_tally_lit(s, c, flush) \
+  { uch cc = (c); \
+    s->d_buf[s->last_lit] = 0; \
+    s->l_buf[s->last_lit++] = cc; \
+    s->dyn_ltree[cc].Freq++; \
+    flush = (s->last_lit == s->lit_bufsize-1); \
+   }
+# define _tr_tally_dist(s, distance, length, flush) \
+  { uch len = (length); \
+    ush dist = (distance); \
+    s->d_buf[s->last_lit] = dist; \
+    s->l_buf[s->last_lit++] = len; \
+    dist--; \
+    s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
+    s->dyn_dtree[d_code(dist)].Freq++; \
+    flush = (s->last_lit == s->lit_bufsize-1); \
+  }
+#else
+# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
+# define _tr_tally_dist(s, distance, length, flush) \
+              flush = _tr_tally(s, distance, length)
+#endif
+
+#endif /* DEFLATE_H */
diff --git a/src/external/tng_io/external/zlib/inffast.c b/src/external/tng_io/external/zlib/inffast.c
new file mode 100644 (file)
index 0000000..bda59ce
--- /dev/null
@@ -0,0 +1,340 @@
+/* inffast.c -- fast decoding
+ * Copyright (C) 1995-2008, 2010, 2013 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifndef ASMINF
+
+/* Allow machine dependent optimization for post-increment or pre-increment.
+   Based on testing to date,
+   Pre-increment preferred for:
+   - PowerPC G3 (Adler)
+   - MIPS R5000 (Randers-Pehrson)
+   Post-increment preferred for:
+   - none
+   No measurable difference:
+   - Pentium III (Anderson)
+   - M68060 (Nikl)
+ */
+#ifdef POSTINC
+#  define OFF 0
+#  define PUP(a) *(a)++
+#else
+#  define OFF 1
+#  define PUP(a) *++(a)
+#endif
+
+/*
+   Decode literal, length, and distance codes and write out the resulting
+   literal and match bytes until either not enough input or output is
+   available, an end-of-block is encountered, or a data error is encountered.
+   When large enough input and output buffers are supplied to inflate(), for
+   example, a 16K input buffer and a 64K output buffer, more than 95% of the
+   inflate execution time is spent in this routine.
+
+   Entry assumptions:
+
+        state->mode == LEN
+        strm->avail_in >= 6
+        strm->avail_out >= 258
+        start >= strm->avail_out
+        state->bits < 8
+
+   On return, state->mode is one of:
+
+        LEN -- ran out of enough output space or enough available input
+        TYPE -- reached end of block code, inflate() to interpret next block
+        BAD -- error in block data
+
+   Notes:
+
+    - The maximum input bits used by a length/distance pair is 15 bits for the
+      length code, 5 bits for the length extra, 15 bits for the distance code,
+      and 13 bits for the distance extra.  This totals 48 bits, or six bytes.
+      Therefore if strm->avail_in >= 6, then there is enough input to avoid
+      checking for available input while decoding.
+
+    - The maximum bytes that a single length/distance pair can output is 258
+      bytes, which is the maximum length that can be coded.  inflate_fast()
+      requires strm->avail_out >= 258 for each loop to avoid checking for
+      output space.
+ */
+void ZLIB_INTERNAL inflate_fast(strm, start)
+z_streamp strm;
+unsigned start;         /* inflate()'s starting value for strm->avail_out */
+{
+    struct inflate_state FAR *state;
+    z_const unsigned char FAR *in;      /* local strm->next_in */
+    z_const unsigned char FAR *last;    /* have enough input while in < last */
+    unsigned char FAR *out;     /* local strm->next_out */
+    unsigned char FAR *beg;     /* inflate()'s initial strm->next_out */
+    unsigned char FAR *end;     /* while out < end, enough space available */
+#ifdef INFLATE_STRICT
+    unsigned dmax;              /* maximum distance from zlib header */
+#endif
+    unsigned wsize;             /* window size or zero if not using window */
+    unsigned whave;             /* valid bytes in the window */
+    unsigned wnext;             /* window write index */
+    unsigned char FAR *window;  /* allocated sliding window, if wsize != 0 */
+    unsigned long hold;         /* local strm->hold */
+    unsigned bits;              /* local strm->bits */
+    code const FAR *lcode;      /* local strm->lencode */
+    code const FAR *dcode;      /* local strm->distcode */
+    unsigned lmask;             /* mask for first level of length codes */
+    unsigned dmask;             /* mask for first level of distance codes */
+    code here;                  /* retrieved table entry */
+    unsigned op;                /* code bits, operation, extra bits, or */
+                                /*  window position, window bytes to copy */
+    unsigned len;               /* match length, unused bytes */
+    unsigned dist;              /* match distance */
+    unsigned char FAR *from;    /* where to copy match from */
+
+    /* copy state to local variables */
+    state = (struct inflate_state FAR *)strm->state;
+    in = strm->next_in - OFF;
+    last = in + (strm->avail_in - 5);
+    out = strm->next_out - OFF;
+    beg = out - (start - strm->avail_out);
+    end = out + (strm->avail_out - 257);
+#ifdef INFLATE_STRICT
+    dmax = state->dmax;
+#endif
+    wsize = state->wsize;
+    whave = state->whave;
+    wnext = state->wnext;
+    window = state->window;
+    hold = state->hold;
+    bits = state->bits;
+    lcode = state->lencode;
+    dcode = state->distcode;
+    lmask = (1U << state->lenbits) - 1;
+    dmask = (1U << state->distbits) - 1;
+
+    /* decode literals and length/distances until end-of-block or not enough
+       input data or output space */
+    do {
+        if (bits < 15) {
+            hold += (unsigned long)(PUP(in)) << bits;
+            bits += 8;
+            hold += (unsigned long)(PUP(in)) << bits;
+            bits += 8;
+        }
+        here = lcode[hold & lmask];
+      dolen:
+        op = (unsigned)(here.bits);
+        hold >>= op;
+        bits -= op;
+        op = (unsigned)(here.op);
+        if (op == 0) {                          /* literal */
+            Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+                    "inflate:         literal '%c'\n" :
+                    "inflate:         literal 0x%02x\n", here.val));
+            PUP(out) = (unsigned char)(here.val);
+        }
+        else if (op & 16) {                     /* length base */
+            len = (unsigned)(here.val);
+            op &= 15;                           /* number of extra bits */
+            if (op) {
+                if (bits < op) {
+                    hold += (unsigned long)(PUP(in)) << bits;
+                    bits += 8;
+                }
+                len += (unsigned)hold & ((1U << op) - 1);
+                hold >>= op;
+                bits -= op;
+            }
+            Tracevv((stderr, "inflate:         length %u\n", len));
+            if (bits < 15) {
+                hold += (unsigned long)(PUP(in)) << bits;
+                bits += 8;
+                hold += (unsigned long)(PUP(in)) << bits;
+                bits += 8;
+            }
+            here = dcode[hold & dmask];
+          dodist:
+            op = (unsigned)(here.bits);
+            hold >>= op;
+            bits -= op;
+            op = (unsigned)(here.op);
+            if (op & 16) {                      /* distance base */
+                dist = (unsigned)(here.val);
+                op &= 15;                       /* number of extra bits */
+                if (bits < op) {
+                    hold += (unsigned long)(PUP(in)) << bits;
+                    bits += 8;
+                    if (bits < op) {
+                        hold += (unsigned long)(PUP(in)) << bits;
+                        bits += 8;
+                    }
+                }
+                dist += (unsigned)hold & ((1U << op) - 1);
+#ifdef INFLATE_STRICT
+                if (dist > dmax) {
+                    strm->msg = (char *)"invalid distance too far back";
+                    state->mode = BAD;
+                    break;
+                }
+#endif
+                hold >>= op;
+                bits -= op;
+                Tracevv((stderr, "inflate:         distance %u\n", dist));
+                op = (unsigned)(out - beg);     /* max distance in output */
+                if (dist > op) {                /* see if copy from window */
+                    op = dist - op;             /* distance back in window */
+                    if (op > whave) {
+                        if (state->sane) {
+                            strm->msg =
+                                (char *)"invalid distance too far back";
+                            state->mode = BAD;
+                            break;
+                        }
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+                        if (len <= op - whave) {
+                            do {
+                                PUP(out) = 0;
+                            } while (--len);
+                            continue;
+                        }
+                        len -= op - whave;
+                        do {
+                            PUP(out) = 0;
+                        } while (--op > whave);
+                        if (op == 0) {
+                            from = out - dist;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--len);
+                            continue;
+                        }
+#endif
+                    }
+                    from = window - OFF;
+                    if (wnext == 0) {           /* very common case */
+                        from += wsize - op;
+                        if (op < len) {         /* some from window */
+                            len -= op;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--op);
+                            from = out - dist;  /* rest from output */
+                        }
+                    }
+                    else if (wnext < op) {      /* wrap around window */
+                        from += wsize + wnext - op;
+                        op -= wnext;
+                        if (op < len) {         /* some from end of window */
+                            len -= op;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--op);
+                            from = window - OFF;
+                            if (wnext < len) {  /* some from start of window */
+                                op = wnext;
+                                len -= op;
+                                do {
+                                    PUP(out) = PUP(from);
+                                } while (--op);
+                                from = out - dist;      /* rest from output */
+                            }
+                        }
+                    }
+                    else {                      /* contiguous in window */
+                        from += wnext - op;
+                        if (op < len) {         /* some from window */
+                            len -= op;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--op);
+                            from = out - dist;  /* rest from output */
+                        }
+                    }
+                    while (len > 2) {
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        len -= 3;
+                    }
+                    if (len) {
+                        PUP(out) = PUP(from);
+                        if (len > 1)
+                            PUP(out) = PUP(from);
+                    }
+                }
+                else {
+                    from = out - dist;          /* copy direct from output */
+                    do {                        /* minimum length is three */
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        len -= 3;
+                    } while (len > 2);
+                    if (len) {
+                        PUP(out) = PUP(from);
+                        if (len > 1)
+                            PUP(out) = PUP(from);
+                    }
+                }
+            }
+            else if ((op & 64) == 0) {          /* 2nd level distance code */
+                here = dcode[here.val + (hold & ((1U << op) - 1))];
+                goto dodist;
+            }
+            else {
+                strm->msg = (char *)"invalid distance code";
+                state->mode = BAD;
+                break;
+            }
+        }
+        else if ((op & 64) == 0) {              /* 2nd level length code */
+            here = lcode[here.val + (hold & ((1U << op) - 1))];
+            goto dolen;
+        }
+        else if (op & 32) {                     /* end-of-block */
+            Tracevv((stderr, "inflate:         end of block\n"));
+            state->mode = TYPE;
+            break;
+        }
+        else {
+            strm->msg = (char *)"invalid literal/length code";
+            state->mode = BAD;
+            break;
+        }
+    } while (in < last && out < end);
+
+    /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+    len = bits >> 3;
+    in -= len;
+    bits -= len << 3;
+    hold &= (1U << bits) - 1;
+
+    /* update state and return */
+    strm->next_in = in + OFF;
+    strm->next_out = out + OFF;
+    strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
+    strm->avail_out = (unsigned)(out < end ?
+                                 257 + (end - out) : 257 - (out - end));
+    state->hold = hold;
+    state->bits = bits;
+    return;
+}
+
+/*
+   inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
+   - Using bit fields for code structure
+   - Different op definition to avoid & for extra bits (do & for table bits)
+   - Three separate decoding do-loops for direct, window, and wnext == 0
+   - Special case for distance > 1 copies to do overlapped load and store copy
+   - Explicit branch predictions (based on measured branch probabilities)
+   - Deferring match copy and interspersed it with decoding subsequent codes
+   - Swapping literal/length else
+   - Swapping window/direct else
+   - Larger unrolled copy loops (three is about right)
+   - Moving len -= 3 statement into middle of loop
+ */
+
+#endif /* !ASMINF */
diff --git a/src/external/tng_io/external/zlib/inffast.h b/src/external/tng_io/external/zlib/inffast.h
new file mode 100644 (file)
index 0000000..e5c1aa4
--- /dev/null
@@ -0,0 +1,11 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-2003, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start));
diff --git a/src/external/tng_io/external/zlib/inffixed.h b/src/external/tng_io/external/zlib/inffixed.h
new file mode 100644 (file)
index 0000000..d628327
--- /dev/null
@@ -0,0 +1,94 @@
+    /* inffixed.h -- table for decoding fixed codes
+     * Generated automatically by makefixed().
+     */
+
+    /* WARNING: this file should *not* be used by applications.
+       It is part of the implementation of this library and is
+       subject to change. Applications should only use zlib.h.
+     */
+
+    static const code lenfix[512] = {
+        {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
+        {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
+        {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
+        {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
+        {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
+        {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
+        {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
+        {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
+        {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
+        {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
+        {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
+        {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
+        {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
+        {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
+        {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
+        {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
+        {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
+        {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
+        {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
+        {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
+        {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
+        {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
+        {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
+        {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
+        {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
+        {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
+        {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
+        {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
+        {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
+        {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
+        {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
+        {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
+        {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
+        {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
+        {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
+        {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
+        {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
+        {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
+        {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
+        {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
+        {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
+        {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
+        {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
+        {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
+        {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
+        {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
+        {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
+        {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
+        {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
+        {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
+        {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
+        {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
+        {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
+        {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
+        {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
+        {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
+        {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
+        {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
+        {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
+        {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
+        {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
+        {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
+        {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
+        {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
+        {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
+        {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
+        {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
+        {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
+        {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
+        {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
+        {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
+        {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
+        {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
+        {0,9,255}
+    };
+
+    static const code distfix[32] = {
+        {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
+        {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
+        {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
+        {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
+        {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
+        {22,5,193},{64,5,0}
+    };
diff --git a/src/external/tng_io/external/zlib/inflate.c b/src/external/tng_io/external/zlib/inflate.c
new file mode 100644 (file)
index 0000000..de1e8cf
--- /dev/null
@@ -0,0 +1,1512 @@
+/* inflate.c -- zlib decompression
+ * Copyright (C) 1995-2012 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * Change history:
+ *
+ * 1.2.beta0    24 Nov 2002
+ * - First version -- complete rewrite of inflate to simplify code, avoid
+ *   creation of window when not needed, minimize use of window when it is
+ *   needed, make inffast.c even faster, implement gzip decoding, and to
+ *   improve code readability and style over the previous zlib inflate code
+ *
+ * 1.2.beta1    25 Nov 2002
+ * - Use pointers for available input and output checking in inffast.c
+ * - Remove input and output counters in inffast.c
+ * - Change inffast.c entry and loop from avail_in >= 7 to >= 6
+ * - Remove unnecessary second byte pull from length extra in inffast.c
+ * - Unroll direct copy to three copies per loop in inffast.c
+ *
+ * 1.2.beta2    4 Dec 2002
+ * - Change external routine names to reduce potential conflicts
+ * - Correct filename to inffixed.h for fixed tables in inflate.c
+ * - Make hbuf[] unsigned char to match parameter type in inflate.c
+ * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset)
+ *   to avoid negation problem on Alphas (64 bit) in inflate.c
+ *
+ * 1.2.beta3    22 Dec 2002
+ * - Add comments on state->bits assertion in inffast.c
+ * - Add comments on op field in inftrees.h
+ * - Fix bug in reuse of allocated window after inflateReset()
+ * - Remove bit fields--back to byte structure for speed
+ * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths
+ * - Change post-increments to pre-increments in inflate_fast(), PPC biased?
+ * - Add compile time option, POSTINC, to use post-increments instead (Intel?)
+ * - Make MATCH copy in inflate() much faster for when inflate_fast() not used
+ * - Use local copies of stream next and avail values, as well as local bit
+ *   buffer and bit count in inflate()--for speed when inflate_fast() not used
+ *
+ * 1.2.beta4    1 Jan 2003
+ * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings
+ * - Move a comment on output buffer sizes from inffast.c to inflate.c
+ * - Add comments in inffast.c to introduce the inflate_fast() routine
+ * - Rearrange window copies in inflate_fast() for speed and simplification
+ * - Unroll last copy for window match in inflate_fast()
+ * - Use local copies of window variables in inflate_fast() for speed
+ * - Pull out common wnext == 0 case for speed in inflate_fast()
+ * - Make op and len in inflate_fast() unsigned for consistency
+ * - Add FAR to lcode and dcode declarations in inflate_fast()
+ * - Simplified bad distance check in inflate_fast()
+ * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new
+ *   source file infback.c to provide a call-back interface to inflate for
+ *   programs like gzip and unzip -- uses window as output buffer to avoid
+ *   window copying
+ *
+ * 1.2.beta5    1 Jan 2003
+ * - Improved inflateBack() interface to allow the caller to provide initial
+ *   input in strm.
+ * - Fixed stored blocks bug in inflateBack()
+ *
+ * 1.2.beta6    4 Jan 2003
+ * - Added comments in inffast.c on effectiveness of POSTINC
+ * - Typecasting all around to reduce compiler warnings
+ * - Changed loops from while (1) or do {} while (1) to for (;;), again to
+ *   make compilers happy
+ * - Changed type of window in inflateBackInit() to unsigned char *
+ *
+ * 1.2.beta7    27 Jan 2003
+ * - Changed many types to unsigned or unsigned short to avoid warnings
+ * - Added inflateCopy() function
+ *
+ * 1.2.0        9 Mar 2003
+ * - Changed inflateBack() interface to provide separate opaque descriptors
+ *   for the in() and out() functions
+ * - Changed inflateBack() argument and in_func typedef to swap the length
+ *   and buffer address return values for the input function
+ * - Check next_in and next_out for Z_NULL on entry to inflate()
+ *
+ * The history for versions after 1.2.0 are in ChangeLog in zlib distribution.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifdef MAKEFIXED
+#  ifndef BUILDFIXED
+#    define BUILDFIXED
+#  endif
+#endif
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+local int updatewindow OF((z_streamp strm, const unsigned char FAR *end,
+                           unsigned copy));
+#ifdef BUILDFIXED
+   void makefixed OF((void));
+#endif
+local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf,
+                              unsigned len));
+
+int ZEXPORT inflateResetKeep(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    strm->total_in = strm->total_out = state->total = 0;
+    strm->msg = Z_NULL;
+    if (state->wrap)        /* to support ill-conceived Java test suite */
+        strm->adler = state->wrap & 1;
+    state->mode = HEAD;
+    state->last = 0;
+    state->havedict = 0;
+    state->dmax = 32768U;
+    state->head = Z_NULL;
+    state->hold = 0;
+    state->bits = 0;
+    state->lencode = state->distcode = state->next = state->codes;
+    state->sane = 1;
+    state->back = -1;
+    Tracev((stderr, "inflate: reset\n"));
+    return Z_OK;
+}
+
+int ZEXPORT inflateReset(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    state->wsize = 0;
+    state->whave = 0;
+    state->wnext = 0;
+    return inflateResetKeep(strm);
+}
+
+int ZEXPORT inflateReset2(strm, windowBits)
+z_streamp strm;
+int windowBits;
+{
+    int wrap;
+    struct inflate_state FAR *state;
+
+    /* get the state */
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+
+    /* extract wrap request from windowBits parameter */
+    if (windowBits < 0) {
+        wrap = 0;
+        windowBits = -windowBits;
+    }
+    else {
+        wrap = (windowBits >> 4) + 1;
+#ifdef GUNZIP
+        if (windowBits < 48)
+            windowBits &= 15;
+#endif
+    }
+
+    /* set number of window bits, free window if different */
+    if (windowBits && (windowBits < 8 || windowBits > 15))
+        return Z_STREAM_ERROR;
+    if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) {
+        ZFREE(strm, state->window);
+        state->window = Z_NULL;
+    }
+
+    /* update state and reset the rest of it */
+    state->wrap = wrap;
+    state->wbits = (unsigned)windowBits;
+    return inflateReset(strm);
+}
+
+int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)
+z_streamp strm;
+int windowBits;
+const char *version;
+int stream_size;
+{
+    int ret;
+    struct inflate_state FAR *state;
+
+    if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+        stream_size != (int)(sizeof(z_stream)))
+        return Z_VERSION_ERROR;
+    if (strm == Z_NULL) return Z_STREAM_ERROR;
+    strm->msg = Z_NULL;                 /* in case we return an error */
+    if (strm->zalloc == (alloc_func)0) {
+#ifdef Z_SOLO
+        return Z_STREAM_ERROR;
+#else
+        strm->zalloc = zcalloc;
+        strm->opaque = (voidpf)0;
+#endif
+    }
+    if (strm->zfree == (free_func)0)
+#ifdef Z_SOLO
+        return Z_STREAM_ERROR;
+#else
+        strm->zfree = zcfree;
+#endif
+    state = (struct inflate_state FAR *)
+            ZALLOC(strm, 1, sizeof(struct inflate_state));
+    if (state == Z_NULL) return Z_MEM_ERROR;
+    Tracev((stderr, "inflate: allocated\n"));
+    strm->state = (struct internal_state FAR *)state;
+    state->window = Z_NULL;
+    ret = inflateReset2(strm, windowBits);
+    if (ret != Z_OK) {
+        ZFREE(strm, state);
+        strm->state = Z_NULL;
+    }
+    return ret;
+}
+
+int ZEXPORT inflateInit_(strm, version, stream_size)
+z_streamp strm;
+const char *version;
+int stream_size;
+{
+    return inflateInit2_(strm, DEF_WBITS, version, stream_size);
+}
+
+int ZEXPORT inflatePrime(strm, bits, value)
+z_streamp strm;
+int bits;
+int value;
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (bits < 0) {
+        state->hold = 0;
+        state->bits = 0;
+        return Z_OK;
+    }
+    if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR;
+    value &= (1L << bits) - 1;
+    state->hold += value << state->bits;
+    state->bits += bits;
+    return Z_OK;
+}
+
+/*
+   Return state with length and distance decoding tables and index sizes set to
+   fixed code decoding.  Normally this returns fixed tables from inffixed.h.
+   If BUILDFIXED is defined, then instead this routine builds the tables the
+   first time it's called, and returns those tables the first time and
+   thereafter.  This reduces the size of the code by about 2K bytes, in
+   exchange for a little execution time.  However, BUILDFIXED should not be
+   used for threaded applications, since the rewriting of the tables and virgin
+   may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+    static int virgin = 1;
+    static code *lenfix, *distfix;
+    static code fixed[544];
+
+    /* build fixed huffman tables if first call (may not be thread safe) */
+    if (virgin) {
+        unsigned sym, bits;
+        static code *next;
+
+        /* literal/length table */
+        sym = 0;
+        while (sym < 144) state->lens[sym++] = 8;
+        while (sym < 256) state->lens[sym++] = 9;
+        while (sym < 280) state->lens[sym++] = 7;
+        while (sym < 288) state->lens[sym++] = 8;
+        next = fixed;
+        lenfix = next;
+        bits = 9;
+        inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+        /* distance table */
+        sym = 0;
+        while (sym < 32) state->lens[sym++] = 5;
+        distfix = next;
+        bits = 5;
+        inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+        /* do this just once */
+        virgin = 0;
+    }
+#else /* !BUILDFIXED */
+#   include "inffixed.h"
+#endif /* BUILDFIXED */
+    state->lencode = lenfix;
+    state->lenbits = 9;
+    state->distcode = distfix;
+    state->distbits = 5;
+}
+
+#ifdef MAKEFIXED
+#include <stdio.h>
+
+/*
+   Write out the inffixed.h that is #include'd above.  Defining MAKEFIXED also
+   defines BUILDFIXED, so the tables are built on the fly.  makefixed() writes
+   those tables to stdout, which would be piped to inffixed.h.  A small program
+   can simply call makefixed to do this:
+
+    void makefixed(void);
+
+    int main(void)
+    {
+        makefixed();
+        return 0;
+    }
+
+   Then that can be linked with zlib built with MAKEFIXED defined and run:
+
+    a.out > inffixed.h
+ */
+void makefixed()
+{
+    unsigned low, size;
+    struct inflate_state state;
+
+    fixedtables(&state);
+    puts("    /* inffixed.h -- table for decoding fixed codes");
+    puts("     * Generated automatically by makefixed().");
+    puts("     */");
+    puts("");
+    puts("    /* WARNING: this file should *not* be used by applications.");
+    puts("       It is part of the implementation of this library and is");
+    puts("       subject to change. Applications should only use zlib.h.");
+    puts("     */");
+    puts("");
+    size = 1U << 9;
+    printf("    static const code lenfix[%u] = {", size);
+    low = 0;
+    for (;;) {
+        if ((low % 7) == 0) printf("\n        ");
+        printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op,
+               state.lencode[low].bits, state.lencode[low].val);
+        if (++low == size) break;
+        putchar(',');
+    }
+    puts("\n    };");
+    size = 1U << 5;
+    printf("\n    static const code distfix[%u] = {", size);
+    low = 0;
+    for (;;) {
+        if ((low % 6) == 0) printf("\n        ");
+        printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
+               state.distcode[low].val);
+        if (++low == size) break;
+        putchar(',');
+    }
+    puts("\n    };");
+}
+#endif /* MAKEFIXED */
+
+/*
+   Update the window with the last wsize (normally 32K) bytes written before
+   returning.  If window does not exist yet, create it.  This is only called
+   when a window is already in use, or when output has been written during this
+   inflate call, but the end of the deflate stream has not been reached yet.
+   It is also called to create a window for dictionary data when a dictionary
+   is loaded.
+
+   Providing output buffers larger than 32K to inflate() should provide a speed
+   advantage, since only the last 32K of output is copied to the sliding window
+   upon return from inflate(), and since all distances after the first 32K of
+   output will fall in the output data, making match copies simpler and faster.
+   The advantage may be dependent on the size of the processor's data caches.
+ */
+local int updatewindow(strm, end, copy)
+z_streamp strm;
+const Bytef *end;
+unsigned copy;
+{
+    struct inflate_state FAR *state;
+    unsigned dist;
+
+    state = (struct inflate_state FAR *)strm->state;
+
+    /* if it hasn't been done already, allocate space for the window */
+    if (state->window == Z_NULL) {
+        state->window = (unsigned char FAR *)
+                        ZALLOC(strm, 1U << state->wbits,
+                               sizeof(unsigned char));
+        if (state->window == Z_NULL) return 1;
+    }
+
+    /* if window not in use yet, initialize */
+    if (state->wsize == 0) {
+        state->wsize = 1U << state->wbits;
+        state->wnext = 0;
+        state->whave = 0;
+    }
+
+    /* copy state->wsize or less output bytes into the circular window */
+    if (copy >= state->wsize) {
+        zmemcpy(state->window, end - state->wsize, state->wsize);
+        state->wnext = 0;
+        state->whave = state->wsize;
+    }
+    else {
+        dist = state->wsize - state->wnext;
+        if (dist > copy) dist = copy;
+        zmemcpy(state->window + state->wnext, end - copy, dist);
+        copy -= dist;
+        if (copy) {
+            zmemcpy(state->window, end - copy, copy);
+            state->wnext = copy;
+            state->whave = state->wsize;
+        }
+        else {
+            state->wnext += dist;
+            if (state->wnext == state->wsize) state->wnext = 0;
+            if (state->whave < state->wsize) state->whave += dist;
+        }
+    }
+    return 0;
+}
+
+/* Macros for inflate(): */
+
+/* check function to use adler32() for zlib or crc32() for gzip */
+#ifdef GUNZIP
+#  define UPDATE(check, buf, len) \
+    (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
+#else
+#  define UPDATE(check, buf, len) adler32(check, buf, len)
+#endif
+
+/* check macros for header crc */
+#ifdef GUNZIP
+#  define CRC2(check, word) \
+    do { \
+        hbuf[0] = (unsigned char)(word); \
+        hbuf[1] = (unsigned char)((word) >> 8); \
+        check = crc32(check, hbuf, 2); \
+    } while (0)
+
+#  define CRC4(check, word) \
+    do { \
+        hbuf[0] = (unsigned char)(word); \
+        hbuf[1] = (unsigned char)((word) >> 8); \
+        hbuf[2] = (unsigned char)((word) >> 16); \
+        hbuf[3] = (unsigned char)((word) >> 24); \
+        check = crc32(check, hbuf, 4); \
+    } while (0)
+#endif
+
+/* Load registers with state in inflate() for speed */
+#define LOAD() \
+    do { \
+        put = strm->next_out; \
+        left = strm->avail_out; \
+        next = strm->next_in; \
+        have = strm->avail_in; \
+        hold = state->hold; \
+        bits = state->bits; \
+    } while (0)
+
+/* Restore state from registers in inflate() */
+#define RESTORE() \
+    do { \
+        strm->next_out = put; \
+        strm->avail_out = left; \
+        strm->next_in = next; \
+        strm->avail_in = have; \
+        state->hold = hold; \
+        state->bits = bits; \
+    } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+    do { \
+        hold = 0; \
+        bits = 0; \
+    } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflate()
+   if there is no input available. */
+#define PULLBYTE() \
+    do { \
+        if (have == 0) goto inf_leave; \
+        have--; \
+        hold += (unsigned long)(*next++) << bits; \
+        bits += 8; \
+    } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator.  If there is
+   not enough available input to do that, then return from inflate(). */
+#define NEEDBITS(n) \
+    do { \
+        while (bits < (unsigned)(n)) \
+            PULLBYTE(); \
+    } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+    ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+    do { \
+        hold >>= (n); \
+        bits -= (unsigned)(n); \
+    } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+    do { \
+        hold >>= bits & 7; \
+        bits -= bits & 7; \
+    } while (0)
+
+/*
+   inflate() uses a state machine to process as much input data and generate as
+   much output data as possible before returning.  The state machine is
+   structured roughly as follows:
+
+    for (;;) switch (state) {
+    ...
+    case STATEn:
+        if (not enough input data or output space to make progress)
+            return;
+        ... make progress ...
+        state = STATEm;
+        break;
+    ...
+    }
+
+   so when inflate() is called again, the same case is attempted again, and
+   if the appropriate resources are provided, the machine proceeds to the
+   next state.  The NEEDBITS() macro is usually the way the state evaluates
+   whether it can proceed or should return.  NEEDBITS() does the return if
+   the requested bits are not available.  The typical use of the BITS macros
+   is:
+
+        NEEDBITS(n);
+        ... do something with BITS(n) ...
+        DROPBITS(n);
+
+   where NEEDBITS(n) either returns from inflate() if there isn't enough
+   input left to load n bits into the accumulator, or it continues.  BITS(n)
+   gives the low n bits in the accumulator.  When done, DROPBITS(n) drops
+   the low n bits off the accumulator.  INITBITS() clears the accumulator
+   and sets the number of available bits to zero.  BYTEBITS() discards just
+   enough bits to put the accumulator on a byte boundary.  After BYTEBITS()
+   and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
+
+   NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
+   if there is no input available.  The decoding of variable length codes uses
+   PULLBYTE() directly in order to pull just enough bytes to decode the next
+   code, and no more.
+
+   Some states loop until they get enough input, making sure that enough
+   state information is maintained to continue the loop where it left off
+   if NEEDBITS() returns in the loop.  For example, want, need, and keep
+   would all have to actually be part of the saved state in case NEEDBITS()
+   returns:
+
+    case STATEw:
+        while (want < need) {
+            NEEDBITS(n);
+            keep[want++] = BITS(n);
+            DROPBITS(n);
+        }
+        state = STATEx;
+    case STATEx:
+
+   As shown above, if the next state is also the next case, then the break
+   is omitted.
+
+   A state may also return if there is not enough output space available to
+   complete that state.  Those states are copying stored data, writing a
+   literal byte, and copying a matching string.
+
+   When returning, a "goto inf_leave" is used to update the total counters,
+   update the check value, and determine whether any progress has been made
+   during that inflate() call in order to return the proper return code.
+   Progress is defined as a change in either strm->avail_in or strm->avail_out.
+   When there is a window, goto inf_leave will update the window with the last
+   output written.  If a goto inf_leave occurs in the middle of decompression
+   and there is no window currently, goto inf_leave will create one and copy
+   output to the window for the next call of inflate().
+
+   In this implementation, the flush parameter of inflate() only affects the
+   return code (per zlib.h).  inflate() always writes as much as possible to
+   strm->next_out, given the space available and the provided input--the effect
+   documented in zlib.h of Z_SYNC_FLUSH.  Furthermore, inflate() always defers
+   the allocation of and copying into a sliding window until necessary, which
+   provides the effect documented in zlib.h for Z_FINISH when the entire input
+   stream available.  So the only thing the flush parameter actually does is:
+   when flush is set to Z_FINISH, inflate() cannot return Z_OK.  Instead it
+   will return Z_BUF_ERROR if it has not reached the end of the stream.
+ */
+
+int ZEXPORT inflate(strm, flush)
+z_streamp strm;
+int flush;
+{
+    struct inflate_state FAR *state;
+    z_const unsigned char FAR *next;    /* next input */
+    unsigned char FAR *put;     /* next output */
+    unsigned have, left;        /* available input and output */
+    unsigned long hold;         /* bit buffer */
+    unsigned bits;              /* bits in bit buffer */
+    unsigned in, out;           /* save starting available input and output */
+    unsigned copy;              /* number of stored or match bytes to copy */
+    unsigned char FAR *from;    /* where to copy match bytes from */
+    code here;                  /* current decoding table entry */
+    code last;                  /* parent table entry */
+    unsigned len;               /* length to copy for repeats, bits to drop */
+    int ret;                    /* return code */
+#ifdef GUNZIP
+    unsigned char hbuf[4];      /* buffer for gzip header crc calculation */
+#endif
+    static const unsigned short order[19] = /* permutation of code lengths */
+        {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+    if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL ||
+        (strm->next_in == Z_NULL && strm->avail_in != 0))
+        return Z_STREAM_ERROR;
+
+    state = (struct inflate_state FAR *)strm->state;
+    if (state->mode == TYPE) state->mode = TYPEDO;      /* skip check */
+    LOAD();
+    in = have;
+    out = left;
+    ret = Z_OK;
+    for (;;)
+        switch (state->mode) {
+        case HEAD:
+            if (state->wrap == 0) {
+                state->mode = TYPEDO;
+                break;
+            }
+            NEEDBITS(16);
+#ifdef GUNZIP
+            if ((state->wrap & 2) && hold == 0x8b1f) {  /* gzip header */
+                state->check = crc32(0L, Z_NULL, 0);
+                CRC2(state->check, hold);
+                INITBITS();
+                state->mode = FLAGS;
+                break;
+            }
+            state->flags = 0;           /* expect zlib header */
+            if (state->head != Z_NULL)
+                state->head->done = -1;
+            if (!(state->wrap & 1) ||   /* check if zlib header allowed */
+#else
+            if (
+#endif
+                ((BITS(8) << 8) + (hold >> 8)) % 31) {
+                strm->msg = (char *)"incorrect header check";
+                state->mode = BAD;
+                break;
+            }
+            if (BITS(4) != Z_DEFLATED) {
+                strm->msg = (char *)"unknown compression method";
+                state->mode = BAD;
+                break;
+            }
+            DROPBITS(4);
+            len = BITS(4) + 8;
+            if (state->wbits == 0)
+                state->wbits = len;
+            else if (len > state->wbits) {
+                strm->msg = (char *)"invalid window size";
+                state->mode = BAD;
+                break;
+            }
+            state->dmax = 1U << len;
+            Tracev((stderr, "inflate:   zlib header ok\n"));
+            strm->adler = state->check = adler32(0L, Z_NULL, 0);
+            state->mode = hold & 0x200 ? DICTID : TYPE;
+            INITBITS();
+            break;
+#ifdef GUNZIP
+        case FLAGS:
+            NEEDBITS(16);
+            state->flags = (int)(hold);
+            if ((state->flags & 0xff) != Z_DEFLATED) {
+                strm->msg = (char *)"unknown compression method";
+                state->mode = BAD;
+                break;
+            }
+            if (state->flags & 0xe000) {
+                strm->msg = (char *)"unknown header flags set";
+                state->mode = BAD;
+                break;
+            }
+            if (state->head != Z_NULL)
+                state->head->text = (int)((hold >> 8) & 1);
+            if (state->flags & 0x0200) CRC2(state->check, hold);
+            INITBITS();
+            state->mode = TIME;
+        case TIME:
+            NEEDBITS(32);
+            if (state->head != Z_NULL)
+                state->head->time = hold;
+            if (state->flags & 0x0200) CRC4(state->check, hold);
+            INITBITS();
+            state->mode = OS;
+        case OS:
+            NEEDBITS(16);
+            if (state->head != Z_NULL) {
+                state->head->xflags = (int)(hold & 0xff);
+                state->head->os = (int)(hold >> 8);
+            }
+            if (state->flags & 0x0200) CRC2(state->check, hold);
+            INITBITS();
+            state->mode = EXLEN;
+        case EXLEN:
+            if (state->flags & 0x0400) {
+                NEEDBITS(16);
+                state->length = (unsigned)(hold);
+                if (state->head != Z_NULL)
+                    state->head->extra_len = (unsigned)hold;
+                if (state->flags & 0x0200) CRC2(state->check, hold);
+                INITBITS();
+            }
+            else if (state->head != Z_NULL)
+                state->head->extra = Z_NULL;
+            state->mode = EXTRA;
+        case EXTRA:
+            if (state->flags & 0x0400) {
+                copy = state->length;
+                if (copy > have) copy = have;
+                if (copy) {
+                    if (state->head != Z_NULL &&
+                        state->head->extra != Z_NULL) {
+                        len = state->head->extra_len - state->length;
+                        zmemcpy(state->head->extra + len, next,
+                                len + copy > state->head->extra_max ?
+                                state->head->extra_max - len : copy);
+                    }
+                    if (state->flags & 0x0200)
+                        state->check = crc32(state->check, next, copy);
+                    have -= copy;
+                    next += copy;
+                    state->length -= copy;
+                }
+                if (state->length) goto inf_leave;
+            }
+            state->length = 0;
+            state->mode = NAME;
+        case NAME:
+            if (state->flags & 0x0800) {
+                if (have == 0) goto inf_leave;
+                copy = 0;
+                do {
+                    len = (unsigned)(next[copy++]);
+                    if (state->head != Z_NULL &&
+                            state->head->name != Z_NULL &&
+                            state->length < state->head->name_max)
+                        state->head->name[state->length++] = len;
+                } while (len && copy < have);
+                if (state->flags & 0x0200)
+                    state->check = crc32(state->check, next, copy);
+                have -= copy;
+                next += copy;
+                if (len) goto inf_leave;
+            }
+            else if (state->head != Z_NULL)
+                state->head->name = Z_NULL;
+            state->length = 0;
+            state->mode = COMMENT;
+        case COMMENT:
+            if (state->flags & 0x1000) {
+                if (have == 0) goto inf_leave;
+                copy = 0;
+                do {
+                    len = (unsigned)(next[copy++]);
+                    if (state->head != Z_NULL &&
+                            state->head->comment != Z_NULL &&
+                            state->length < state->head->comm_max)
+                        state->head->comment[state->length++] = len;
+                } while (len && copy < have);
+                if (state->flags & 0x0200)
+                    state->check = crc32(state->check, next, copy);
+                have -= copy;
+                next += copy;
+                if (len) goto inf_leave;
+            }
+            else if (state->head != Z_NULL)
+                state->head->comment = Z_NULL;
+            state->mode = HCRC;
+        case HCRC:
+            if (state->flags & 0x0200) {
+                NEEDBITS(16);
+                if (hold != (state->check & 0xffff)) {
+                    strm->msg = (char *)"header crc mismatch";
+                    state->mode = BAD;
+                    break;
+                }
+                INITBITS();
+            }
+            if (state->head != Z_NULL) {
+                state->head->hcrc = (int)((state->flags >> 9) & 1);
+                state->head->done = 1;
+            }
+            strm->adler = state->check = crc32(0L, Z_NULL, 0);
+            state->mode = TYPE;
+            break;
+#endif
+        case DICTID:
+            NEEDBITS(32);
+            strm->adler = state->check = ZSWAP32(hold);
+            INITBITS();
+            state->mode = DICT;
+        case DICT:
+            if (state->havedict == 0) {
+                RESTORE();
+                return Z_NEED_DICT;
+            }
+            strm->adler = state->check = adler32(0L, Z_NULL, 0);
+            state->mode = TYPE;
+        case TYPE:
+            if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;
+        case TYPEDO:
+            if (state->last) {
+                BYTEBITS();
+                state->mode = CHECK;
+                break;
+            }
+            NEEDBITS(3);
+            state->last = BITS(1);
+            DROPBITS(1);
+            switch (BITS(2)) {
+            case 0:                             /* stored block */
+                Tracev((stderr, "inflate:     stored block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = STORED;
+                break;
+            case 1:                             /* fixed block */
+                fixedtables(state);
+                Tracev((stderr, "inflate:     fixed codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = LEN_;             /* decode codes */
+                if (flush == Z_TREES) {
+                    DROPBITS(2);
+                    goto inf_leave;
+                }
+                break;
+            case 2:                             /* dynamic block */
+                Tracev((stderr, "inflate:     dynamic codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = TABLE;
+                break;
+            case 3:
+                strm->msg = (char *)"invalid block type";
+                state->mode = BAD;
+            }
+            DROPBITS(2);
+            break;
+        case STORED:
+            BYTEBITS();                         /* go to byte boundary */
+            NEEDBITS(32);
+            if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+                strm->msg = (char *)"invalid stored block lengths";
+                state->mode = BAD;
+                break;
+            }
+            state->length = (unsigned)hold & 0xffff;
+            Tracev((stderr, "inflate:       stored length %u\n",
+                    state->length));
+            INITBITS();
+            state->mode = COPY_;
+            if (flush == Z_TREES) goto inf_leave;
+        case COPY_:
+            state->mode = COPY;
+        case COPY:
+            copy = state->length;
+            if (copy) {
+                if (copy > have) copy = have;
+                if (copy > left) copy = left;
+                if (copy == 0) goto inf_leave;
+                zmemcpy(put, next, copy);
+                have -= copy;
+                next += copy;
+                left -= copy;
+                put += copy;
+                state->length -= copy;
+                break;
+            }
+            Tracev((stderr, "inflate:       stored end\n"));
+            state->mode = TYPE;
+            break;
+        case TABLE:
+            NEEDBITS(14);
+            state->nlen = BITS(5) + 257;
+            DROPBITS(5);
+            state->ndist = BITS(5) + 1;
+            DROPBITS(5);
+            state->ncode = BITS(4) + 4;
+            DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+            if (state->nlen > 286 || state->ndist > 30) {
+                strm->msg = (char *)"too many length or distance symbols";
+                state->mode = BAD;
+                break;
+            }
+#endif
+            Tracev((stderr, "inflate:       table sizes ok\n"));
+            state->have = 0;
+            state->mode = LENLENS;
+        case LENLENS:
+            while (state->have < state->ncode) {
+                NEEDBITS(3);
+                state->lens[order[state->have++]] = (unsigned short)BITS(3);
+                DROPBITS(3);
+            }
+            while (state->have < 19)
+                state->lens[order[state->have++]] = 0;
+            state->next = state->codes;
+            state->lencode = (const code FAR *)(state->next);
+            state->lenbits = 7;
+            ret = inflate_table(CODES, state->lens, 19, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid code lengths set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       code lengths ok\n"));
+            state->have = 0;
+            state->mode = CODELENS;
+        case CODELENS:
+            while (state->have < state->nlen + state->ndist) {
+                for (;;) {
+                    here = state->lencode[BITS(state->lenbits)];
+                    if ((unsigned)(here.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                if (here.val < 16) {
+                    DROPBITS(here.bits);
+                    state->lens[state->have++] = here.val;
+                }
+                else {
+                    if (here.val == 16) {
+                        NEEDBITS(here.bits + 2);
+                        DROPBITS(here.bits);
+                        if (state->have == 0) {
+                            strm->msg = (char *)"invalid bit length repeat";
+                            state->mode = BAD;
+                            break;
+                        }
+                        len = state->lens[state->have - 1];
+                        copy = 3 + BITS(2);
+                        DROPBITS(2);
+                    }
+                    else if (here.val == 17) {
+                        NEEDBITS(here.bits + 3);
+                        DROPBITS(here.bits);
+                        len = 0;
+                        copy = 3 + BITS(3);
+                        DROPBITS(3);
+                    }
+                    else {
+                        NEEDBITS(here.bits + 7);
+                        DROPBITS(here.bits);
+                        len = 0;
+                        copy = 11 + BITS(7);
+                        DROPBITS(7);
+                    }
+                    if (state->have + copy > state->nlen + state->ndist) {
+                        strm->msg = (char *)"invalid bit length repeat";
+                        state->mode = BAD;
+                        break;
+                    }
+                    while (copy--)
+                        state->lens[state->have++] = (unsigned short)len;
+                }
+            }
+
+            /* handle error breaks in while */
+            if (state->mode == BAD) break;
+
+            /* check for end-of-block code (better have one) */
+            if (state->lens[256] == 0) {
+                strm->msg = (char *)"invalid code -- missing end-of-block";
+                state->mode = BAD;
+                break;
+            }
+
+            /* build code tables -- note: do not change the lenbits or distbits
+               values here (9 and 6) without reading the comments in inftrees.h
+               concerning the ENOUGH constants, which depend on those values */
+            state->next = state->codes;
+            state->lencode = (const code FAR *)(state->next);
+            state->lenbits = 9;
+            ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid literal/lengths set";
+                state->mode = BAD;
+                break;
+            }
+            state->distcode = (const code FAR *)(state->next);
+            state->distbits = 6;
+            ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+                            &(state->next), &(state->distbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid distances set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       codes ok\n"));
+            state->mode = LEN_;
+            if (flush == Z_TREES) goto inf_leave;
+        case LEN_:
+            state->mode = LEN;
+        case LEN:
+            if (have >= 6 && left >= 258) {
+                RESTORE();
+                inflate_fast(strm, out);
+                LOAD();
+                if (state->mode == TYPE)
+                    state->back = -1;
+                break;
+            }
+            state->back = 0;
+            for (;;) {
+                here = state->lencode[BITS(state->lenbits)];
+                if ((unsigned)(here.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if (here.op && (here.op & 0xf0) == 0) {
+                last = here;
+                for (;;) {
+                    here = state->lencode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + here.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+                state->back += last.bits;
+            }
+            DROPBITS(here.bits);
+            state->back += here.bits;
+            state->length = (unsigned)here.val;
+            if ((int)(here.op) == 0) {
+                Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+                        "inflate:         literal '%c'\n" :
+                        "inflate:         literal 0x%02x\n", here.val));
+                state->mode = LIT;
+                break;
+            }
+            if (here.op & 32) {
+                Tracevv((stderr, "inflate:         end of block\n"));
+                state->back = -1;
+                state->mode = TYPE;
+                break;
+            }
+            if (here.op & 64) {
+                strm->msg = (char *)"invalid literal/length code";
+                state->mode = BAD;
+                break;
+            }
+            state->extra = (unsigned)(here.op) & 15;
+            state->mode = LENEXT;
+        case LENEXT:
+            if (state->extra) {
+                NEEDBITS(state->extra);
+                state->length += BITS(state->extra);
+                DROPBITS(state->extra);
+                state->back += state->extra;
+            }
+            Tracevv((stderr, "inflate:         length %u\n", state->length));
+            state->was = state->length;
+            state->mode = DIST;
+        case DIST:
+            for (;;) {
+                here = state->distcode[BITS(state->distbits)];
+                if ((unsigned)(here.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if ((here.op & 0xf0) == 0) {
+                last = here;
+                for (;;) {
+                    here = state->distcode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + here.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+                state->back += last.bits;
+            }
+            DROPBITS(here.bits);
+            state->back += here.bits;
+            if (here.op & 64) {
+                strm->msg = (char *)"invalid distance code";
+                state->mode = BAD;
+                break;
+            }
+            state->offset = (unsigned)here.val;
+            state->extra = (unsigned)(here.op) & 15;
+            state->mode = DISTEXT;
+        case DISTEXT:
+            if (state->extra) {
+                NEEDBITS(state->extra);
+                state->offset += BITS(state->extra);
+                DROPBITS(state->extra);
+                state->back += state->extra;
+            }
+#ifdef INFLATE_STRICT
+            if (state->offset > state->dmax) {
+                strm->msg = (char *)"invalid distance too far back";
+                state->mode = BAD;
+                break;
+            }
+#endif
+            Tracevv((stderr, "inflate:         distance %u\n", state->offset));
+            state->mode = MATCH;
+        case MATCH:
+            if (left == 0) goto inf_leave;
+            copy = out - left;
+            if (state->offset > copy) {         /* copy from window */
+                copy = state->offset - copy;
+                if (copy > state->whave) {
+                    if (state->sane) {
+                        strm->msg = (char *)"invalid distance too far back";
+                        state->mode = BAD;
+                        break;
+                    }
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+                    Trace((stderr, "inflate.c too far\n"));
+                    copy -= state->whave;
+                    if (copy > state->length) copy = state->length;
+                    if (copy > left) copy = left;
+                    left -= copy;
+                    state->length -= copy;
+                    do {
+                        *put++ = 0;
+                    } while (--copy);
+                    if (state->length == 0) state->mode = LEN;
+                    break;
+#endif
+                }
+                if (copy > state->wnext) {
+                    copy -= state->wnext;
+                    from = state->window + (state->wsize - copy);
+                }
+                else
+                    from = state->window + (state->wnext - copy);
+                if (copy > state->length) copy = state->length;
+            }
+            else {                              /* copy from output */
+                from = put - state->offset;
+                copy = state->length;
+            }
+            if (copy > left) copy = left;
+            left -= copy;
+            state->length -= copy;
+            do {
+                *put++ = *from++;
+            } while (--copy);
+            if (state->length == 0) state->mode = LEN;
+            break;
+        case LIT:
+            if (left == 0) goto inf_leave;
+            *put++ = (unsigned char)(state->length);
+            left--;
+            state->mode = LEN;
+            break;
+        case CHECK:
+            if (state->wrap) {
+                NEEDBITS(32);
+                out -= left;
+                strm->total_out += out;
+                state->total += out;
+                if (out)
+                    strm->adler = state->check =
+                        UPDATE(state->check, put - out, out);
+                out = left;
+                if ((
+#ifdef GUNZIP
+                     state->flags ? hold :
+#endif
+                     ZSWAP32(hold)) != state->check) {
+                    strm->msg = (char *)"incorrect data check";
+                    state->mode = BAD;
+                    break;
+                }
+                INITBITS();
+                Tracev((stderr, "inflate:   check matches trailer\n"));
+            }
+#ifdef GUNZIP
+            state->mode = LENGTH;
+        case LENGTH:
+            if (state->wrap && state->flags) {
+                NEEDBITS(32);
+                if (hold != (state->total & 0xffffffffUL)) {
+                    strm->msg = (char *)"incorrect length check";
+                    state->mode = BAD;
+                    break;
+                }
+                INITBITS();
+                Tracev((stderr, "inflate:   length matches trailer\n"));
+            }
+#endif
+            state->mode = DONE;
+        case DONE:
+            ret = Z_STREAM_END;
+            goto inf_leave;
+        case BAD:
+            ret = Z_DATA_ERROR;
+            goto inf_leave;
+        case MEM:
+            return Z_MEM_ERROR;
+        case SYNC:
+        default:
+            return Z_STREAM_ERROR;
+        }
+
+    /*
+       Return from inflate(), updating the total counts and the check value.
+       If there was no progress during the inflate() call, return a buffer
+       error.  Call updatewindow() to create and/or update the window state.
+       Note: a memory error from inflate() is non-recoverable.
+     */
+  inf_leave:
+    RESTORE();
+    if (state->wsize || (out != strm->avail_out && state->mode < BAD &&
+            (state->mode < CHECK || flush != Z_FINISH)))
+        if (updatewindow(strm, strm->next_out, out - strm->avail_out)) {
+            state->mode = MEM;
+            return Z_MEM_ERROR;
+        }
+    in -= strm->avail_in;
+    out -= strm->avail_out;
+    strm->total_in += in;
+    strm->total_out += out;
+    state->total += out;
+    if (state->wrap && out)
+        strm->adler = state->check =
+            UPDATE(state->check, strm->next_out - out, out);
+    strm->data_type = state->bits + (state->last ? 64 : 0) +
+                      (state->mode == TYPE ? 128 : 0) +
+                      (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0);
+    if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
+        ret = Z_BUF_ERROR;
+    return ret;
+}
+
+int ZEXPORT inflateEnd(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+    if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+        return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (state->window != Z_NULL) ZFREE(strm, state->window);
+    ZFREE(strm, strm->state);
+    strm->state = Z_NULL;
+    Tracev((stderr, "inflate: end\n"));
+    return Z_OK;
+}
+
+int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength)
+z_streamp strm;
+Bytef *dictionary;
+uInt *dictLength;
+{
+    struct inflate_state FAR *state;
+
+    /* check state */
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+
+    /* copy dictionary */
+    if (state->whave && dictionary != Z_NULL) {
+        zmemcpy(dictionary, state->window + state->wnext,
+                state->whave - state->wnext);
+        zmemcpy(dictionary + state->whave - state->wnext,
+                state->window, state->wnext);
+    }
+    if (dictLength != Z_NULL)
+        *dictLength = state->whave;
+    return Z_OK;
+}
+
+int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength)
+z_streamp strm;
+const Bytef *dictionary;
+uInt dictLength;
+{
+    struct inflate_state FAR *state;
+    unsigned long dictid;
+    int ret;
+
+    /* check state */
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (state->wrap != 0 && state->mode != DICT)
+        return Z_STREAM_ERROR;
+
+    /* check for correct dictionary identifier */
+    if (state->mode == DICT) {
+        dictid = adler32(0L, Z_NULL, 0);
+        dictid = adler32(dictid, dictionary, dictLength);
+        if (dictid != state->check)
+            return Z_DATA_ERROR;
+    }
+
+    /* copy dictionary to window using updatewindow(), which will amend the
+       existing dictionary if appropriate */
+    ret = updatewindow(strm, dictionary + dictLength, dictLength);
+    if (ret) {
+        state->mode = MEM;
+        return Z_MEM_ERROR;
+    }
+    state->havedict = 1;
+    Tracev((stderr, "inflate:   dictionary set\n"));
+    return Z_OK;
+}
+
+int ZEXPORT inflateGetHeader(strm, head)
+z_streamp strm;
+gz_headerp head;
+{
+    struct inflate_state FAR *state;
+
+    /* check state */
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;
+
+    /* save header structure */
+    state->head = head;
+    head->done = 0;
+    return Z_OK;
+}
+
+/*
+   Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff.  Return when found
+   or when out of input.  When called, *have is the number of pattern bytes
+   found in order so far, in 0..3.  On return *have is updated to the new
+   state.  If on return *have equals four, then the pattern was found and the
+   return value is how many bytes were read including the last byte of the
+   pattern.  If *have is less than four, then the pattern has not been found
+   yet and the return value is len.  In the latter case, syncsearch() can be
+   called again with more data and the *have state.  *have is initialized to
+   zero for the first call.
+ */
+local unsigned syncsearch(have, buf, len)
+unsigned FAR *have;
+const unsigned char FAR *buf;
+unsigned len;
+{
+    unsigned got;
+    unsigned next;
+
+    got = *have;
+    next = 0;
+    while (next < len && got < 4) {
+        if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))
+            got++;
+        else if (buf[next])
+            got = 0;
+        else
+            got = 4 - got;
+        next++;
+    }
+    *have = got;
+    return next;
+}
+
+int ZEXPORT inflateSync(strm)
+z_streamp strm;
+{
+    unsigned len;               /* number of bytes to look at or looked at */
+    unsigned long in, out;      /* temporary to save total_in and total_out */
+    unsigned char buf[4];       /* to restore bit buffer to byte string */
+    struct inflate_state FAR *state;
+
+    /* check parameters */
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
+
+    /* if first time, start search in bit buffer */
+    if (state->mode != SYNC) {
+        state->mode = SYNC;
+        state->hold <<= state->bits & 7;
+        state->bits -= state->bits & 7;
+        len = 0;
+        while (state->bits >= 8) {
+            buf[len++] = (unsigned char)(state->hold);
+            state->hold >>= 8;
+            state->bits -= 8;
+        }
+        state->have = 0;
+        syncsearch(&(state->have), buf, len);
+    }
+
+    /* search available input */
+    len = syncsearch(&(state->have), strm->next_in, strm->avail_in);
+    strm->avail_in -= len;
+    strm->next_in += len;
+    strm->total_in += len;
+
+    /* return no joy or set up to restart inflate() on a new block */
+    if (state->have != 4) return Z_DATA_ERROR;
+    in = strm->total_in;  out = strm->total_out;
+    inflateReset(strm);
+    strm->total_in = in;  strm->total_out = out;
+    state->mode = TYPE;
+    return Z_OK;
+}
+
+/*
+   Returns true if inflate is currently at the end of a block generated by
+   Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+   implementation to provide an additional safety check. PPP uses
+   Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
+   block. When decompressing, PPP checks that at the end of input packet,
+   inflate is waiting for these length bytes.
+ */
+int ZEXPORT inflateSyncPoint(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    return state->mode == STORED && state->bits == 0;
+}
+
+int ZEXPORT inflateCopy(dest, source)
+z_streamp dest;
+z_streamp source;
+{
+    struct inflate_state FAR *state;
+    struct inflate_state FAR *copy;
+    unsigned char FAR *window;
+    unsigned wsize;
+
+    /* check input */
+    if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL ||
+        source->zalloc == (alloc_func)0 || source->zfree == (free_func)0)
+        return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)source->state;
+
+    /* allocate space */
+    copy = (struct inflate_state FAR *)
+           ZALLOC(source, 1, sizeof(struct inflate_state));
+    if (copy == Z_NULL) return Z_MEM_ERROR;
+    window = Z_NULL;
+    if (state->window != Z_NULL) {
+        window = (unsigned char FAR *)
+                 ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));
+        if (window == Z_NULL) {
+            ZFREE(source, copy);
+            return Z_MEM_ERROR;
+        }
+    }
+
+    /* copy state */
+    zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));
+    zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state));
+    if (state->lencode >= state->codes &&
+        state->lencode <= state->codes + ENOUGH - 1) {
+        copy->lencode = copy->codes + (state->lencode - state->codes);
+        copy->distcode = copy->codes + (state->distcode - state->codes);
+    }
+    copy->next = copy->codes + (state->next - state->codes);
+    if (window != Z_NULL) {
+        wsize = 1U << state->wbits;
+        zmemcpy(window, state->window, wsize);
+    }
+    copy->window = window;
+    dest->state = (struct internal_state FAR *)copy;
+    return Z_OK;
+}
+
+int ZEXPORT inflateUndermine(strm, subvert)
+z_streamp strm;
+int subvert;
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    state->sane = !subvert;
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+    return Z_OK;
+#else
+    state->sane = 1;
+    return Z_DATA_ERROR;
+#endif
+}
+
+long ZEXPORT inflateMark(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return ~0xFFFFL; /* Original code returned -1L << 16, but that is undefined behaviour */
+    state = (struct inflate_state FAR *)strm->state;
+    return ((long)(state->back) << 16) +
+        (state->mode == COPY ? state->length :
+            (state->mode == MATCH ? state->was - state->length : 0));
+}
diff --git a/src/external/tng_io/external/zlib/inflate.h b/src/external/tng_io/external/zlib/inflate.h
new file mode 100644 (file)
index 0000000..95f4986
--- /dev/null
@@ -0,0 +1,122 @@
+/* inflate.h -- internal inflate state definition
+ * Copyright (C) 1995-2009 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+   trailer decoding by inflate().  NO_GZIP would be used to avoid linking in
+   the crc code when it is not needed.  For shared libraries, gzip decoding
+   should be left enabled. */
+#ifndef NO_GZIP
+#  define GUNZIP
+#endif
+
+/* Possible inflate modes between inflate() calls */
+typedef enum {
+    HEAD,       /* i: waiting for magic header */
+    FLAGS,      /* i: waiting for method and flags (gzip) */
+    TIME,       /* i: waiting for modification time (gzip) */
+    OS,         /* i: waiting for extra flags and operating system (gzip) */
+    EXLEN,      /* i: waiting for extra length (gzip) */
+    EXTRA,      /* i: waiting for extra bytes (gzip) */
+    NAME,       /* i: waiting for end of file name (gzip) */
+    COMMENT,    /* i: waiting for end of comment (gzip) */
+    HCRC,       /* i: waiting for header crc (gzip) */
+    DICTID,     /* i: waiting for dictionary check value */
+    DICT,       /* waiting for inflateSetDictionary() call */
+        TYPE,       /* i: waiting for type bits, including last-flag bit */
+        TYPEDO,     /* i: same, but skip check to exit inflate on new block */
+        STORED,     /* i: waiting for stored size (length and complement) */
+        COPY_,      /* i/o: same as COPY below, but only first time in */
+        COPY,       /* i/o: waiting for input or output to copy stored block */
+        TABLE,      /* i: waiting for dynamic block table lengths */
+        LENLENS,    /* i: waiting for code length code lengths */
+        CODELENS,   /* i: waiting for length/lit and distance code lengths */
+            LEN_,       /* i: same as LEN below, but only first time in */
+            LEN,        /* i: waiting for length/lit/eob code */
+            LENEXT,     /* i: waiting for length extra bits */
+            DIST,       /* i: waiting for distance code */
+            DISTEXT,    /* i: waiting for distance extra bits */
+            MATCH,      /* o: waiting for output space to copy string */
+            LIT,        /* o: waiting for output space to write literal */
+    CHECK,      /* i: waiting for 32-bit check value */
+    LENGTH,     /* i: waiting for 32-bit length (gzip) */
+    DONE,       /* finished check, done -- remain here until reset */
+    BAD,        /* got a data error -- remain here until reset */
+    MEM,        /* got an inflate() memory error -- remain here until reset */
+    SYNC        /* looking for synchronization bytes to restart inflate() */
+} inflate_mode;
+
+/*
+    State transitions between above modes -
+
+    (most modes can go to BAD or MEM on error -- not shown for clarity)
+
+    Process header:
+        HEAD -> (gzip) or (zlib) or (raw)
+        (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT ->
+                  HCRC -> TYPE
+        (zlib) -> DICTID or TYPE
+        DICTID -> DICT -> TYPE
+        (raw) -> TYPEDO
+    Read deflate blocks:
+            TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK
+            STORED -> COPY_ -> COPY -> TYPE
+            TABLE -> LENLENS -> CODELENS -> LEN_
+            LEN_ -> LEN
+    Read deflate codes in fixed or dynamic block:
+                LEN -> LENEXT or LIT or TYPE
+                LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
+                LIT -> LEN
+    Process trailer:
+        CHECK -> LENGTH -> DONE
+ */
+
+/* state maintained between inflate() calls.  Approximately 10K bytes. */
+struct inflate_state {
+    inflate_mode mode;          /* current inflate mode */
+    int last;                   /* true if processing last block */
+    int wrap;                   /* bit 0 true for zlib, bit 1 true for gzip */
+    int havedict;               /* true if dictionary provided */
+    int flags;                  /* gzip header method and flags (0 if zlib) */
+    unsigned dmax;              /* zlib header max distance (INFLATE_STRICT) */
+    unsigned long check;        /* protected copy of check value */
+    unsigned long total;        /* protected copy of output count */
+    gz_headerp head;            /* where to save gzip header information */
+        /* sliding window */
+    unsigned wbits;             /* log base 2 of requested window size */
+    unsigned wsize;             /* window size or zero if not using window */
+    unsigned whave;             /* valid bytes in the window */
+    unsigned wnext;             /* window write index */
+    unsigned char FAR *window;  /* allocated sliding window, if needed */
+        /* bit accumulator */
+    unsigned long hold;         /* input bit accumulator */
+    unsigned bits;              /* number of bits in "in" */
+        /* for string and stored block copying */
+    unsigned length;            /* literal or length of data to copy */
+    unsigned offset;            /* distance back to copy string from */
+        /* for table and code decoding */
+    unsigned extra;             /* extra bits needed */
+        /* fixed and dynamic code tables */
+    code const FAR *lencode;    /* starting table for length/literal codes */
+    code const FAR *distcode;   /* starting table for distance codes */
+    unsigned lenbits;           /* index bits for lencode */
+    unsigned distbits;          /* index bits for distcode */
+        /* dynamic table building */
+    unsigned ncode;             /* number of code length code lengths */
+    unsigned nlen;              /* number of length code lengths */
+    unsigned ndist;             /* number of distance code lengths */
+    unsigned have;              /* number of code lengths in lens[] */
+    code FAR *next;             /* next available space in codes[] */
+    unsigned short lens[320];   /* temporary storage for code lengths */
+    unsigned short work[288];   /* work area for code table building */
+    code codes[ENOUGH];         /* space for code tables */
+    int sane;                   /* if false, allow invalid distance too far */
+    int back;                   /* bits back of last unprocessed length/lit */
+    unsigned was;               /* initial length of match */
+};
diff --git a/src/external/tng_io/external/zlib/inftrees.c b/src/external/tng_io/external/zlib/inftrees.c
new file mode 100644 (file)
index 0000000..44d89cf
--- /dev/null
@@ -0,0 +1,306 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2013 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#define MAXBITS 15
+
+const char inflate_copyright[] =
+   " inflate 1.2.8 Copyright 1995-2013 Mark Adler ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+
+/*
+   Build a set of tables to decode the provided canonical Huffman code.
+   The code lengths are lens[0..codes-1].  The result starts at *table,
+   whose indices are 0..2^bits-1.  work is a writable array of at least
+   lens shorts, which is used as a work area.  type is the type of code
+   to be generated, CODES, LENS, or DISTS.  On return, zero is success,
+   -1 is an invalid code, and +1 means that ENOUGH isn't enough.  table
+   on return points to the next available entry's address.  bits is the
+   requested root table index bits, and on return it is the actual root
+   table index bits.  It will differ if the request is greater than the
+   longest code or if it is less than the shortest code.
+ */
+int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work)
+codetype type;
+unsigned short FAR *lens;
+unsigned codes;
+code FAR * FAR *table;
+unsigned FAR *bits;
+unsigned short FAR *work;
+{
+    unsigned len;               /* a code's length in bits */
+    unsigned sym;               /* index of code symbols */
+    unsigned min, max;          /* minimum and maximum code lengths */
+    unsigned root;              /* number of index bits for root table */
+    unsigned curr;              /* number of index bits for current table */
+    unsigned drop;              /* code bits to drop for sub-table */
+    int left;                   /* number of prefix codes available */
+    unsigned used;              /* code entries in table used */
+    unsigned huff;              /* Huffman code */
+    unsigned incr;              /* for incrementing code, index */
+    unsigned fill;              /* index for replicating entries */
+    unsigned low;               /* low bits for current root entry */
+    unsigned mask;              /* mask for low root bits */
+    code here;                  /* table entry for duplication */
+    code FAR *next;             /* next available space in table */
+    const unsigned short FAR *base;     /* base value table to use */
+    const unsigned short FAR *extra;    /* extra bits table to use */
+    int end;                    /* use base and extra for symbol > end */
+    unsigned short count[MAXBITS+1];    /* number of codes of each length */
+    unsigned short offs[MAXBITS+1];     /* offsets in table for each length */
+    static const unsigned short lbase[31] = { /* Length codes 257..285 base */
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+    static const unsigned short lext[31] = { /* Length codes 257..285 extra */
+        16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
+        19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78};
+    static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577, 0, 0};
+    static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
+        16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
+        23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
+        28, 28, 29, 29, 64, 64};
+
+    /*
+       Process a set of code lengths to create a canonical Huffman code.  The
+       code lengths are lens[0..codes-1].  Each length corresponds to the
+       symbols 0..codes-1.  The Huffman code is generated by first sorting the
+       symbols by length from short to long, and retaining the symbol order
+       for codes with equal lengths.  Then the code starts with all zero bits
+       for the first code of the shortest length, and the codes are integer
+       increments for the same length, and zeros are appended as the length
+       increases.  For the deflate format, these bits are stored backwards
+       from their more natural integer increment ordering, and so when the
+       decoding tables are built in the large loop below, the integer codes
+       are incremented backwards.
+
+       This routine assumes, but does not check, that all of the entries in
+       lens[] are in the range 0..MAXBITS.  The caller must assure this.
+       1..MAXBITS is interpreted as that code length.  zero means that that
+       symbol does not occur in this code.
+
+       The codes are sorted by computing a count of codes for each length,
+       creating from that a table of starting indices for each length in the
+       sorted table, and then entering the symbols in order in the sorted
+       table.  The sorted table is work[], with that space being provided by
+       the caller.
+
+       The length counts are used for other purposes as well, i.e. finding
+       the minimum and maximum length codes, determining if there are any
+       codes at all, checking for a valid set of lengths, and looking ahead
+       at length counts to determine sub-table sizes when building the
+       decoding tables.
+     */
+
+    /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+    for (len = 0; len <= MAXBITS; len++)
+        count[len] = 0;
+    for (sym = 0; sym < codes; sym++)
+        count[lens[sym]]++;
+
+    /* bound code lengths, force root to be within code lengths */
+    root = *bits;
+    for (max = MAXBITS; max >= 1; max--)
+        if (count[max] != 0) break;
+    if (root > max) root = max;
+    if (max == 0) {                     /* no symbols to code at all */
+        here.op = (unsigned char)64;    /* invalid code marker */
+        here.bits = (unsigned char)1;
+        here.val = (unsigned short)0;
+        *(*table)++ = here;             /* make a table to force an error */
+        *(*table)++ = here;
+        *bits = 1;
+        return 0;     /* no symbols, but wait for decoding to report error */
+    }
+    for (min = 1; min < max; min++)
+        if (count[min] != 0) break;
+    if (root < min) root = min;
+
+    /* check for an over-subscribed or incomplete set of lengths */
+    left = 1;
+    for (len = 1; len <= MAXBITS; len++) {
+        left <<= 1;
+        left -= count[len];
+        if (left < 0) return -1;        /* over-subscribed */
+    }
+    if (left > 0 && (type == CODES || max != 1))
+        return -1;                      /* incomplete set */
+
+    /* generate offsets into symbol table for each length for sorting */
+    offs[1] = 0;
+    for (len = 1; len < MAXBITS; len++)
+        offs[len + 1] = offs[len] + count[len];
+
+    /* sort symbols by length, by symbol order within each length */
+    for (sym = 0; sym < codes; sym++)
+        if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
+
+    /*
+       Create and fill in decoding tables.  In this loop, the table being
+       filled is at next and has curr index bits.  The code being used is huff
+       with length len.  That code is converted to an index by dropping drop
+       bits off of the bottom.  For codes where len is less than drop + curr,
+       those top drop + curr - len bits are incremented through all values to
+       fill the table with replicated entries.
+
+       root is the number of index bits for the root table.  When len exceeds
+       root, sub-tables are created pointed to by the root entry with an index
+       of the low root bits of huff.  This is saved in low to check for when a
+       new sub-table should be started.  drop is zero when the root table is
+       being filled, and drop is root when sub-tables are being filled.
+
+       When a new sub-table is needed, it is necessary to look ahead in the
+       code lengths to determine what size sub-table is needed.  The length
+       counts are used for this, and so count[] is decremented as codes are
+       entered in the tables.
+
+       used keeps track of how many table entries have been allocated from the
+       provided *table space.  It is checked for LENS and DIST tables against
+       the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
+       the initial root table size constants.  See the comments in inftrees.h
+       for more information.
+
+       sym increments through all symbols, and the loop terminates when
+       all codes of length max, i.e. all codes, have been processed.  This
+       routine permits incomplete codes, so another loop after this one fills
+       in the rest of the decoding tables with invalid code markers.
+     */
+
+    /* set up for code type */
+    switch (type) {
+    case CODES:
+        base = extra = work;    /* dummy value--not used */
+        end = 19;
+        break;
+    case LENS:
+        base = lbase;
+        base -= 257;
+        extra = lext;
+        extra -= 257;
+        end = 256;
+        break;
+    default:            /* DISTS */
+        base = dbase;
+        extra = dext;
+        end = -1;
+    }
+
+    /* initialize state for loop */
+    huff = 0;                   /* starting code */
+    sym = 0;                    /* starting code symbol */
+    len = min;                  /* starting code length */
+    next = *table;              /* current table to fill in */
+    curr = root;                /* current table index bits */
+    drop = 0;                   /* current bits to drop from code for index */
+    low = (unsigned)(-1);       /* trigger new sub-table when len > root */
+    used = 1U << root;          /* use root table entries */
+    mask = used - 1;            /* mask for comparing low */
+
+    /* check available table space */
+    if ((type == LENS && used > ENOUGH_LENS) ||
+        (type == DISTS && used > ENOUGH_DISTS))
+        return 1;
+
+    /* process all codes and make table entries */
+    for (;;) {
+        /* create table entry */
+        here.bits = (unsigned char)(len - drop);
+        if ((int)(work[sym]) < end) {
+            here.op = (unsigned char)0;
+            here.val = work[sym];
+        }
+        else if ((int)(work[sym]) > end) {
+            here.op = (unsigned char)(extra[work[sym]]);
+            here.val = base[work[sym]];
+        }
+        else {
+            here.op = (unsigned char)(32 + 64);         /* end of block */
+            here.val = 0;
+        }
+
+        /* replicate for those indices with low len bits equal to huff */
+        incr = 1U << (len - drop);
+        fill = 1U << curr;
+        min = fill;                 /* save offset to next table */
+        do {
+            fill -= incr;
+            next[(huff >> drop) + fill] = here;
+        } while (fill != 0);
+
+        /* backwards increment the len-bit code huff */
+        incr = 1U << (len - 1);
+        while (huff & incr)
+            incr >>= 1;
+        if (incr != 0) {
+            huff &= incr - 1;
+            huff += incr;
+        }
+        else
+            huff = 0;
+
+        /* go to next symbol, update count, len */
+        sym++;
+        if (--(count[len]) == 0) {
+            if (len == max) break;
+            len = lens[work[sym]];
+        }
+
+        /* create new sub-table if needed */
+        if (len > root && (huff & mask) != low) {
+            /* if first time, transition to sub-tables */
+            if (drop == 0)
+                drop = root;
+
+            /* increment past last table */
+            next += min;            /* here min is 1 << curr */
+
+            /* determine length of next table */
+            curr = len - drop;
+            left = (int)(1 << curr);
+            while (curr + drop < max) {
+                left -= count[curr + drop];
+                if (left <= 0) break;
+                curr++;
+                left <<= 1;
+            }
+
+            /* check for enough space */
+            used += 1U << curr;
+            if ((type == LENS && used > ENOUGH_LENS) ||
+                (type == DISTS && used > ENOUGH_DISTS))
+                return 1;
+
+            /* point entry in root table to sub-table */
+            low = huff & mask;
+            (*table)[low].op = (unsigned char)curr;
+            (*table)[low].bits = (unsigned char)root;
+            (*table)[low].val = (unsigned short)(next - *table);
+        }
+    }
+
+    /* fill in remaining table entry if code is incomplete (guaranteed to have
+       at most one remaining entry, since if the code is incomplete, the
+       maximum code length that was allowed to get this far is one bit) */
+    if (huff != 0) {
+        here.op = (unsigned char)64;            /* invalid code marker */
+        here.bits = (unsigned char)(len - drop);
+        here.val = (unsigned short)0;
+        next[huff] = here;
+    }
+
+    /* set return parameters */
+    *table += used;
+    *bits = root;
+    return 0;
+}
diff --git a/src/external/tng_io/external/zlib/inftrees.h b/src/external/tng_io/external/zlib/inftrees.h
new file mode 100644 (file)
index 0000000..baa53a0
--- /dev/null
@@ -0,0 +1,62 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-2005, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* Structure for decoding tables.  Each entry provides either the
+   information needed to do the operation requested by the code that
+   indexed that table entry, or it provides a pointer to another
+   table that indexes more bits of the code.  op indicates whether
+   the entry is a pointer to another table, a literal, a length or
+   distance, an end-of-block, or an invalid code.  For a table
+   pointer, the low four bits of op is the number of index bits of
+   that table.  For a length or distance, the low four bits of op
+   is the number of extra bits to get after the code.  bits is
+   the number of bits in this code or part of the code to drop off
+   of the bit buffer.  val is the actual byte to output in the case
+   of a literal, the base length or distance, or the offset from
+   the current table to the next table.  Each entry is four bytes. */
+typedef struct {
+    unsigned char op;           /* operation, extra bits, table bits */
+    unsigned char bits;         /* bits in this part of the code */
+    unsigned short val;         /* offset in table or code value */
+} code;
+
+/* op values as set by inflate_table():
+    00000000 - literal
+    0000tttt - table link, tttt != 0 is the number of table index bits
+    0001eeee - length or distance, eeee is the number of extra bits
+    01100000 - end of block
+    01000000 - invalid code
+ */
+
+/* Maximum size of the dynamic table.  The maximum number of code structures is
+   1444, which is the sum of 852 for literal/length codes and 592 for distance
+   codes.  These values were found by exhaustive searches using the program
+   examples/enough.c found in the zlib distribtution.  The arguments to that
+   program are the number of symbols, the initial root table size, and the
+   maximum bit length of a code.  "enough 286 9 15" for literal/length codes
+   returns returns 852, and "enough 30 6 15" for distance codes returns 592.
+   The initial root table size (9 or 6) is found in the fifth argument of the
+   inflate_table() calls in inflate.c and infback.c.  If the root table size is
+   changed, then these maximum sizes would be need to be recalculated and
+   updated. */
+#define ENOUGH_LENS 852
+#define ENOUGH_DISTS 592
+#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS)
+
+/* Type of code to build for inflate_table() */
+typedef enum {
+    CODES,
+    LENS,
+    DISTS
+} codetype;
+
+int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens,
+                             unsigned codes, code FAR * FAR *table,
+                             unsigned FAR *bits, unsigned short FAR *work));
diff --git a/src/external/tng_io/external/zlib/trees.c b/src/external/tng_io/external/zlib/trees.c
new file mode 100644 (file)
index 0000000..1fd7759
--- /dev/null
@@ -0,0 +1,1226 @@
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-2012 Jean-loup Gailly
+ * detect_data_type() function provided freely by Cosmin Truta, 2006
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process uses several Huffman trees. The more
+ *      common source values are represented by shorter bit sequences.
+ *
+ *      Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values).  The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ *      Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ *      Storer, James A.
+ *          Data Compression:  Methods and Theory, pp. 49-50.
+ *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
+ *
+ *      Sedgewick, R.
+ *          Algorithms, p290.
+ *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* @(#) $Id$ */
+
+/* #define GEN_TREES_H */
+
+#include "deflate.h"
+
+#ifdef DEBUG
+#  include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6      16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10    17
+/* repeat a zero length 3-10 times  (3 bits of repeat count) */
+
+#define REPZ_11_138  18
+/* repeat a zero length 11-138 times  (7 bits of repeat count) */
+
+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+   = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
+   = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local const uch bl_order[BL_CODES]
+   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+#define DIST_CODE_LEN  512 /* see definition of array dist_code below */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+/* non ANSI compilers may not accept trees.h */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+uch _dist_code[DIST_CODE_LEN];
+/* Distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+uch _length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#else
+#  include "trees.h"
+#endif /* GEN_TREES_H */
+
+struct static_tree_desc_s {
+    const ct_data *static_tree;  /* static tree or NULL */
+    const intf *extra_bits;      /* extra bits for each code or NULL */
+    int     extra_base;          /* base index for extra_bits */
+    int     elems;               /* max number of elements in the tree */
+    int     max_length;          /* max bit length for the codes */
+};
+
+local static_tree_desc  static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc  static_d_desc =
+{static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS};
+
+local static_tree_desc  static_bl_desc =
+{(const ct_data *)0, extra_blbits, 0,   BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block     OF((deflate_state *s));
+local void pqdownheap     OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen     OF((deflate_state *s, tree_desc *desc));
+local void gen_codes      OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree     OF((deflate_state *s, tree_desc *desc));
+local void scan_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local int  build_bl_tree  OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+                              int blcodes));
+local void compress_block OF((deflate_state *s, const ct_data *ltree,
+                              const ct_data *dtree));
+local int  detect_data_type OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup      OF((deflate_state *s));
+local void bi_flush       OF((deflate_state *s));
+local void copy_block     OF((deflate_state *s, charf *buf, unsigned len,
+                              int header));
+
+#ifdef GEN_TREES_H
+local void gen_trees_header OF((void));
+#endif
+
+#ifndef DEBUG
+#  define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+   /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+#  define send_code(s, c, tree) \
+     { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+       send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+    put_byte(s, (uch)((w) & 0xff)); \
+    put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG
+local void send_bits      OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+    deflate_state *s;
+    int value;  /* value to send */
+    int length; /* number of bits */
+{
+    Tracevv((stderr," l %2d v %4x ", length, value));
+    Assert(length > 0 && length <= 15, "invalid length");
+    s->bits_sent += (ulg)length;
+
+    /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+     * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+     * unused bits in value.
+     */
+    if (s->bi_valid > (int)Buf_size - length) {
+        s->bi_buf |= (ush)value << s->bi_valid;
+        put_short(s, s->bi_buf);
+        s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+        s->bi_valid += length - Buf_size;
+    } else {
+        s->bi_buf |= (ush)value << s->bi_valid;
+        s->bi_valid += length;
+    }
+}
+#else /* !DEBUG */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+  if (s->bi_valid > (int)Buf_size - len) {\
+    int val = value;\
+    s->bi_buf |= (ush)val << s->bi_valid;\
+    put_short(s, s->bi_buf);\
+    s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+    s->bi_valid += len - Buf_size;\
+  } else {\
+    s->bi_buf |= (ush)(value) << s->bi_valid;\
+    s->bi_valid += len;\
+  }\
+}
+#endif /* DEBUG */
+
+
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables.
+ */
+local void tr_static_init()
+{
+#if defined(GEN_TREES_H) || !defined(STDC)
+    static int static_init_done = 0;
+    int n;        /* iterates over tree elements */
+    int bits;     /* bit counter */
+    int length;   /* length value */
+    int code;     /* code value */
+    int dist;     /* distance index */
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    if (static_init_done) return;
+
+    /* For some embedded targets, global variables are not initialized: */
+#ifdef NO_INIT_GLOBAL_POINTERS
+    static_l_desc.static_tree = static_ltree;
+    static_l_desc.extra_bits = extra_lbits;
+    static_d_desc.static_tree = static_dtree;
+    static_d_desc.extra_bits = extra_dbits;
+    static_bl_desc.extra_bits = extra_blbits;
+#endif
+
+    /* Initialize the mapping length (0..255) -> length code (0..28) */
+    length = 0;
+    for (code = 0; code < LENGTH_CODES-1; code++) {
+        base_length[code] = length;
+        for (n = 0; n < (1<<extra_lbits[code]); n++) {
+            _length_code[length++] = (uch)code;
+        }
+    }
+    Assert (length == 256, "tr_static_init: length != 256");
+    /* Note that the length 255 (match length 258) can be represented
+     * in two different ways: code 284 + 5 bits or code 285, so we
+     * overwrite length_code[255] to use the best encoding:
+     */
+    _length_code[length-1] = (uch)code;
+
+    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+    dist = 0;
+    for (code = 0 ; code < 16; code++) {
+        base_dist[code] = dist;
+        for (n = 0; n < (1<<extra_dbits[code]); n++) {
+            _dist_code[dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: dist != 256");
+    dist >>= 7; /* from now on, all distances are divided by 128 */
+    for ( ; code < D_CODES; code++) {
+        base_dist[code] = dist << 7;
+        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+            _dist_code[256 + dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+    /* Construct the codes of the static literal tree */
+    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+    n = 0;
+    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+    /* Codes 286 and 287 do not exist, but we must include them in the
+     * tree construction to get a canonical Huffman tree (longest code
+     * all ones)
+     */
+    gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+    /* The static distance tree is trivial: */
+    for (n = 0; n < D_CODES; n++) {
+        static_dtree[n].Len = 5;
+        static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+    }
+    static_init_done = 1;
+
+#  ifdef GEN_TREES_H
+    gen_trees_header();
+#  endif
+#endif /* defined(GEN_TREES_H) || !defined(STDC) */
+}
+
+/* ===========================================================================
+ * Genererate the file trees.h describing the static trees.
+ */
+#ifdef GEN_TREES_H
+#  ifndef DEBUG
+#    include <stdio.h>
+#  endif
+
+#  define SEPARATOR(i, last, width) \
+      ((i) == (last)? "\n};\n\n" :    \
+       ((i) % (width) == (width)-1 ? ",\n" : ", "))
+
+void gen_trees_header()
+{
+    FILE *header = fopen("trees.h", "w");
+    int i;
+
+    Assert (header != NULL, "Can't open trees.h");
+    fprintf(header,
+            "/* header created automatically with -DGEN_TREES_H */\n\n");
+
+    fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");
+    for (i = 0; i < L_CODES+2; i++) {
+        fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,
+                static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
+    }
+
+    fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");
+    for (i = 0; i < D_CODES; i++) {
+        fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,
+                static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
+    }
+
+    fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n");
+    for (i = 0; i < DIST_CODE_LEN; i++) {
+        fprintf(header, "%2u%s", _dist_code[i],
+                SEPARATOR(i, DIST_CODE_LEN-1, 20));
+    }
+
+    fprintf(header,
+        "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");
+    for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {
+        fprintf(header, "%2u%s", _length_code[i],
+                SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
+    }
+
+    fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");
+    for (i = 0; i < LENGTH_CODES; i++) {
+        fprintf(header, "%1u%s", base_length[i],
+                SEPARATOR(i, LENGTH_CODES-1, 20));
+    }
+
+    fprintf(header, "local const int base_dist[D_CODES] = {\n");
+    for (i = 0; i < D_CODES; i++) {
+        fprintf(header, "%5u%s", base_dist[i],
+                SEPARATOR(i, D_CODES-1, 10));
+    }
+
+    fclose(header);
+}
+#endif /* GEN_TREES_H */
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void ZLIB_INTERNAL _tr_init(s)
+    deflate_state *s;
+{
+    tr_static_init();
+
+    s->l_desc.dyn_tree = s->dyn_ltree;
+    s->l_desc.stat_desc = &static_l_desc;
+
+    s->d_desc.dyn_tree = s->dyn_dtree;
+    s->d_desc.stat_desc = &static_d_desc;
+
+    s->bl_desc.dyn_tree = s->bl_tree;
+    s->bl_desc.stat_desc = &static_bl_desc;
+
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+#ifdef DEBUG
+    s->compressed_len = 0L;
+    s->bits_sent = 0L;
+#endif
+
+    /* Initialize the first block of the first file: */
+    init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+    deflate_state *s;
+{
+    int n; /* iterates over tree elements */
+
+    /* Initialize the trees. */
+    for (n = 0; n < L_CODES;  n++) s->dyn_ltree[n].Freq = 0;
+    for (n = 0; n < D_CODES;  n++) s->dyn_dtree[n].Freq = 0;
+    for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+    s->dyn_ltree[END_BLOCK].Freq = 1;
+    s->opt_len = s->static_len = 0L;
+    s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+    top = s->heap[SMALLEST]; \
+    s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+    pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+   (tree[n].Freq < tree[m].Freq || \
+   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+    deflate_state *s;
+    ct_data *tree;  /* the tree to restore */
+    int k;               /* node to move down */
+{
+    int v = s->heap[k];
+    int j = k << 1;  /* left son of k */
+    while (j <= s->heap_len) {
+        /* Set j to the smallest of the two sons: */
+        if (j < s->heap_len &&
+            smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+            j++;
+        }
+        /* Exit if v is smaller than both sons */
+        if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+        /* Exchange v with the smallest son */
+        s->heap[k] = s->heap[j];  k = j;
+
+        /* And continue down the tree, setting j to the left son of k */
+        j <<= 1;
+    }
+    s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ *    above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ *     array bl_count contains the frequencies for each bit length.
+ *     The length opt_len is updated; static_len is also updated if stree is
+ *     not null.
+ */
+local void gen_bitlen(s, desc)
+    deflate_state *s;
+    tree_desc *desc;    /* the tree descriptor */
+{
+    ct_data *tree        = desc->dyn_tree;
+    int max_code         = desc->max_code;
+    const ct_data *stree = desc->stat_desc->static_tree;
+    const intf *extra    = desc->stat_desc->extra_bits;
+    int base             = desc->stat_desc->extra_base;
+    int max_length       = desc->stat_desc->max_length;
+    int h;              /* heap index */
+    int n, m;           /* iterate over the tree elements */
+    int bits;           /* bit length */
+    int xbits;          /* extra bits */
+    ush f;              /* frequency */
+    int overflow = 0;   /* number of elements with bit length too large */
+
+    for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+    /* In a first pass, compute the optimal bit lengths (which may
+     * overflow in the case of the bit length tree).
+     */
+    tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+    for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+        n = s->heap[h];
+        bits = tree[tree[n].Dad].Len + 1;
+        if (bits > max_length) bits = max_length, overflow++;
+        tree[n].Len = (ush)bits;
+        /* We overwrite tree[n].Dad which is no longer needed */
+
+        if (n > max_code) continue; /* not a leaf node */
+
+        s->bl_count[bits]++;
+        xbits = 0;
+        if (n >= base) xbits = extra[n-base];
+        f = tree[n].Freq;
+        s->opt_len += (ulg)f * (bits + xbits);
+        if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+    }
+    if (overflow == 0) return;
+
+    Trace((stderr,"\nbit length overflow\n"));
+    /* This happens for example on obj2 and pic of the Calgary corpus */
+
+    /* Find the first bit length which could increase: */
+    do {
+        bits = max_length-1;
+        while (s->bl_count[bits] == 0) bits--;
+        s->bl_count[bits]--;      /* move one leaf down the tree */
+        s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+        s->bl_count[max_length]--;
+        /* The brother of the overflow item also moves one step up,
+         * but this does not affect bl_count[max_length]
+         */
+        overflow -= 2;
+    } while (overflow > 0);
+
+    /* Now recompute all bit lengths, scanning in increasing frequency.
+     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+     * lengths instead of fixing only the wrong ones. This idea is taken
+     * from 'ar' written by Haruhiko Okumura.)
+     */
+    for (bits = max_length; bits != 0; bits--) {
+        n = s->bl_count[bits];
+        while (n != 0) {
+            m = s->heap[--h];
+            if (m > max_code) continue;
+            if ((unsigned) tree[m].Len != (unsigned) bits) {
+                Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+                s->opt_len += ((long)bits - (long)tree[m].Len)
+                              *(long)tree[m].Freq;
+                tree[m].Len = (ush)bits;
+            }
+            n--;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ *     zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+    ct_data *tree;             /* the tree to decorate */
+    int max_code;              /* largest code with non zero frequency */
+    ushf *bl_count;            /* number of codes at each bit length */
+{
+    ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+    ush code = 0;              /* running code value */
+    int bits;                  /* bit index */
+    int n;                     /* code index */
+
+    /* The distribution counts are first used to generate the code values
+     * without bit reversal.
+     */
+    for (bits = 1; bits <= MAX_BITS; bits++) {
+        next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+    }
+    /* Check that the bit counts in bl_count are consistent. The last code
+     * must be all ones.
+     */
+    Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+            "inconsistent bit counts");
+    Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+    for (n = 0;  n <= max_code; n++) {
+        int len = tree[n].Len;
+        if (len == 0) continue;
+        /* Now reverse the bits */
+        tree[n].Code = bi_reverse(next_code[len]++, len);
+
+        Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+    }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ *     and corresponding code. The length opt_len is updated; static_len is
+ *     also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+    deflate_state *s;
+    tree_desc *desc; /* the tree descriptor */
+{
+    ct_data *tree         = desc->dyn_tree;
+    const ct_data *stree  = desc->stat_desc->static_tree;
+    int elems             = desc->stat_desc->elems;
+    int n, m;          /* iterate over heap elements */
+    int max_code = -1; /* largest code with non zero frequency */
+    int node;          /* new node being created */
+
+    /* Construct the initial heap, with least frequent element in
+     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+     * heap[0] is not used.
+     */
+    s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+    for (n = 0; n < elems; n++) {
+        if (tree[n].Freq != 0) {
+            s->heap[++(s->heap_len)] = max_code = n;
+            s->depth[n] = 0;
+        } else {
+            tree[n].Len = 0;
+        }
+    }
+
+    /* The pkzip format requires that at least one distance code exists,
+     * and that at least one bit should be sent even if there is only one
+     * possible code. So to avoid special checks later on we force at least
+     * two codes of non zero frequency.
+     */
+    while (s->heap_len < 2) {
+        node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+        tree[node].Freq = 1;
+        s->depth[node] = 0;
+        s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+        /* node is 0 or 1 so it does not have extra bits */
+    }
+    desc->max_code = max_code;
+
+    /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+     * establish sub-heaps of increasing lengths:
+     */
+    for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+    /* Construct the Huffman tree by repeatedly combining the least two
+     * frequent nodes.
+     */
+    node = elems;              /* next internal node of the tree */
+    do {
+        pqremove(s, tree, n);  /* n = node of least frequency */
+        m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+        s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+        s->heap[--(s->heap_max)] = m;
+
+        /* Create a new node father of n and m */
+        tree[node].Freq = tree[n].Freq + tree[m].Freq;
+        s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ?
+                                s->depth[n] : s->depth[m]) + 1);
+        tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+        if (tree == s->bl_tree) {
+            fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+        }
+#endif
+        /* and insert the new node in the heap */
+        s->heap[SMALLEST] = node++;
+        pqdownheap(s, tree, SMALLEST);
+
+    } while (s->heap_len >= 2);
+
+    s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+    /* At this point, the fields freq and dad are set. We can now
+     * generate the bit lengths.
+     */
+    gen_bitlen(s, (tree_desc *)desc);
+
+    /* The field len is now set, we can generate the bit codes */
+    gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree;   /* the tree to be scanned */
+    int max_code;    /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    if (nextlen == 0) max_count = 138, min_count = 3;
+    tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            s->bl_tree[curlen].Freq += count;
+        } else if (curlen != 0) {
+            if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+            s->bl_tree[REP_3_6].Freq++;
+        } else if (count <= 10) {
+            s->bl_tree[REPZ_3_10].Freq++;
+        } else {
+            s->bl_tree[REPZ_11_138].Freq++;
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree; /* the tree to be scanned */
+    int max_code;       /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    /* tree[max_code+1].Len = -1; */  /* guard already set */
+    if (nextlen == 0) max_count = 138, min_count = 3;
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+        } else if (curlen != 0) {
+            if (curlen != prevlen) {
+                send_code(s, curlen, s->bl_tree); count--;
+            }
+            Assert(count >= 3 && count <= 6, " 3_6?");
+            send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+        } else if (count <= 10) {
+            send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+        } else {
+            send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+    deflate_state *s;
+{
+    int max_blindex;  /* index of last bit length code of non zero freq */
+
+    /* Determine the bit length frequencies for literal and distance trees */
+    scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+    scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+    /* Build the bit length tree: */
+    build_tree(s, (tree_desc *)(&(s->bl_desc)));
+    /* opt_len now includes the length of the tree representations, except
+     * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+     */
+
+    /* Determine the number of bit length codes to send. The pkzip format
+     * requires that at least 4 bit length codes be sent. (appnote.txt says
+     * 3 but the actual value used is 4.)
+     */
+    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+        if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+    }
+    /* Update opt_len to include the bit length tree and counts */
+    s->opt_len += 3*(max_blindex+1) + 5+5+4;
+    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+            s->opt_len, s->static_len));
+
+    return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+    deflate_state *s;
+    int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+    int rank;                    /* index in bl_order */
+
+    Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+            "too many codes");
+    Tracev((stderr, "\nbl counts: "));
+    send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+    send_bits(s, dcodes-1,   5);
+    send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */
+    for (rank = 0; rank < blcodes; rank++) {
+        Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+        send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+    }
+    Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+    Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+    Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last)
+    deflate_state *s;
+    charf *buf;       /* input block */
+    ulg stored_len;   /* length of input block */
+    int last;         /* one if this is the last block for a file */
+{
+    send_bits(s, (STORED_BLOCK<<1)+last, 3);    /* send block type */
+#ifdef DEBUG
+    s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+    s->compressed_len += (stored_len + 4) << 3;
+#endif
+    copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* ===========================================================================
+ * Flush the bits in the bit buffer to pending output (leaves at most 7 bits)
+ */
+void ZLIB_INTERNAL _tr_flush_bits(s)
+    deflate_state *s;
+{
+    bi_flush(s);
+}
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ */
+void ZLIB_INTERNAL _tr_align(s)
+    deflate_state *s;
+{
+    send_bits(s, STATIC_TREES<<1, 3);
+    send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+    s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+#endif
+    bi_flush(s);
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file.
+ */
+void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
+    deflate_state *s;
+    charf *buf;       /* input block, or NULL if too old */
+    ulg stored_len;   /* length of input block */
+    int last;         /* one if this is the last block for a file */
+{
+    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+    int max_blindex = 0;  /* index of last bit length code of non zero freq */
+
+    /* Build the Huffman trees unless a stored block is forced */
+    if (s->level > 0) {
+
+        /* Check if the file is binary or text */
+        if (s->strm->data_type == Z_UNKNOWN)
+            s->strm->data_type = detect_data_type(s);
+
+        /* Construct the literal and distance trees */
+        build_tree(s, (tree_desc *)(&(s->l_desc)));
+        Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+                s->static_len));
+
+        build_tree(s, (tree_desc *)(&(s->d_desc)));
+        Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+                s->static_len));
+        /* At this point, opt_len and static_len are the total bit lengths of
+         * the compressed block data, excluding the tree representations.
+         */
+
+        /* Build the bit length tree for the above two trees, and get the index
+         * in bl_order of the last bit length code to send.
+         */
+        max_blindex = build_bl_tree(s);
+
+        /* Determine the best encoding. Compute the block lengths in bytes. */
+        opt_lenb = (s->opt_len+3+7)>>3;
+        static_lenb = (s->static_len+3+7)>>3;
+
+        Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+                opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+                s->last_lit));
+
+        if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+    } else {
+        Assert(buf != (char*)0, "lost buf");
+        opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+    }
+
+#ifdef FORCE_STORED
+    if (buf != (char*)0) { /* force stored block */
+#else
+    if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+                       /* 4: two words for the lengths */
+#endif
+        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+         * Otherwise we can't have processed more than WSIZE input bytes since
+         * the last block flush, because compression would have been
+         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+         * transform a block into a stored block.
+         */
+        _tr_stored_block(s, buf, stored_len, last);
+
+#ifdef FORCE_STATIC
+    } else if (static_lenb >= 0) { /* force static trees */
+#else
+    } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) {
+#endif
+        send_bits(s, (STATIC_TREES<<1)+last, 3);
+        compress_block(s, (const ct_data *)static_ltree,
+                       (const ct_data *)static_dtree);
+#ifdef DEBUG
+        s->compressed_len += 3 + s->static_len;
+#endif
+    } else {
+        send_bits(s, (DYN_TREES<<1)+last, 3);
+        send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+                       max_blindex+1);
+        compress_block(s, (const ct_data *)s->dyn_ltree,
+                       (const ct_data *)s->dyn_dtree);
+#ifdef DEBUG
+        s->compressed_len += 3 + s->opt_len;
+#endif
+    }
+    Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+    /* The above check is made mod 2^32, for files larger than 512 MB
+     * and uLong implemented on 32 bits.
+     */
+    init_block(s);
+
+    if (last) {
+        bi_windup(s);
+#ifdef DEBUG
+        s->compressed_len += 7;  /* align on byte boundary */
+#endif
+    }
+    Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+           s->compressed_len-7*last));
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int ZLIB_INTERNAL _tr_tally (s, dist, lc)
+    deflate_state *s;
+    unsigned dist;  /* distance of matched string */
+    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+    s->d_buf[s->last_lit] = (ush)dist;
+    s->l_buf[s->last_lit++] = (uch)lc;
+    if (dist == 0) {
+        /* lc is the unmatched char */
+        s->dyn_ltree[lc].Freq++;
+    } else {
+        s->matches++;
+        /* Here, lc is the match length - MIN_MATCH */
+        dist--;             /* dist = match distance - 1 */
+        Assert((ush)dist < (ush)MAX_DIST(s) &&
+               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+               (ush)d_code(dist) < (ush)D_CODES,  "_tr_tally: bad match");
+
+        s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
+        s->dyn_dtree[d_code(dist)].Freq++;
+    }
+
+#ifdef TRUNCATE_BLOCK
+    /* Try to guess if it is profitable to stop the current block here */
+    if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
+        /* Compute an upper bound for the compressed length */
+        ulg out_length = (ulg)s->last_lit*8L;
+        ulg in_length = (ulg)((long)s->strstart - s->block_start);
+        int dcode;
+        for (dcode = 0; dcode < D_CODES; dcode++) {
+            out_length += (ulg)s->dyn_dtree[dcode].Freq *
+                (5L+extra_dbits[dcode]);
+        }
+        out_length >>= 3;
+        Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+               s->last_lit, in_length, out_length,
+               100L - out_length*100L/in_length));
+        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+    }
+#endif
+    return (s->last_lit == s->lit_bufsize-1);
+    /* We avoid equality with lit_bufsize because of wraparound at 64K
+     * on 16 bit machines and because stored blocks are restricted to
+     * 64K-1 bytes.
+     */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+    deflate_state *s;
+    const ct_data *ltree; /* literal tree */
+    const ct_data *dtree; /* distance tree */
+{
+    unsigned dist;      /* distance of matched string */
+    int lc;             /* match length or unmatched char (if dist == 0) */
+    unsigned lx = 0;    /* running index in l_buf */
+    unsigned code;      /* the code to send */
+    int extra;          /* number of extra bits to send */
+
+    if (s->last_lit != 0) do {
+        dist = s->d_buf[lx];
+        lc = s->l_buf[lx++];
+        if (dist == 0) {
+            send_code(s, lc, ltree); /* send a literal byte */
+            Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+        } else {
+            /* Here, lc is the match length - MIN_MATCH */
+            code = _length_code[lc];
+            send_code(s, code+LITERALS+1, ltree); /* send the length code */
+            extra = extra_lbits[code];
+            if (extra != 0) {
+                lc -= base_length[code];
+                send_bits(s, lc, extra);       /* send the extra length bits */
+            }
+            dist--; /* dist is now the match distance - 1 */
+            code = d_code(dist);
+            Assert (code < D_CODES, "bad d_code");
+
+            send_code(s, code, dtree);       /* send the distance code */
+            extra = extra_dbits[code];
+            if (extra != 0) {
+                dist -= base_dist[code];
+                send_bits(s, dist, extra);   /* send the extra distance bits */
+            }
+        } /* literal or match pair ? */
+
+        /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+        Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
+               "pendingBuf overflow");
+
+    } while (lx < s->last_lit);
+
+    send_code(s, END_BLOCK, ltree);
+}
+
+/* ===========================================================================
+ * Check if the data type is TEXT or BINARY, using the following algorithm:
+ * - TEXT if the two conditions below are satisfied:
+ *    a) There are no non-portable control characters belonging to the
+ *       "black list" (0..6, 14..25, 28..31).
+ *    b) There is at least one printable character belonging to the
+ *       "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
+ * - BINARY otherwise.
+ * - The following partially-portable control characters form a
+ *   "gray list" that is ignored in this detection algorithm:
+ *   (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
+ * IN assertion: the fields Freq of dyn_ltree are set.
+ */
+local int detect_data_type(s)
+    deflate_state *s;
+{
+    /* black_mask is the bit mask of black-listed bytes
+     * set bits 0..6, 14..25, and 28..31
+     * 0xf3ffc07f = binary 11110011111111111100000001111111
+     */
+    unsigned long black_mask = 0xf3ffc07fUL;
+    int n;
+
+    /* Check for non-textual ("black-listed") bytes. */
+    for (n = 0; n <= 31; n++, black_mask >>= 1)
+        if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0))
+            return Z_BINARY;
+
+    /* Check for textual ("white-listed") bytes. */
+    if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0
+            || s->dyn_ltree[13].Freq != 0)
+        return Z_TEXT;
+    for (n = 32; n < LITERALS; n++)
+        if (s->dyn_ltree[n].Freq != 0)
+            return Z_TEXT;
+
+    /* There are no "black-listed" or "white-listed" bytes:
+     * this stream either is empty or has tolerated ("gray-listed") bytes only.
+     */
+    return Z_BINARY;
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+    unsigned code; /* the value to invert */
+    int len;       /* its bit length */
+{
+    register unsigned res = 0;
+    do {
+        res |= code & 1;
+        code >>= 1, res <<= 1;
+    } while (--len > 0);
+    return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+    deflate_state *s;
+{
+    if (s->bi_valid == 16) {
+        put_short(s, s->bi_buf);
+        s->bi_buf = 0;
+        s->bi_valid = 0;
+    } else if (s->bi_valid >= 8) {
+        put_byte(s, (Byte)s->bi_buf);
+        s->bi_buf >>= 8;
+        s->bi_valid -= 8;
+    }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+    deflate_state *s;
+{
+    if (s->bi_valid > 8) {
+        put_short(s, s->bi_buf);
+    } else if (s->bi_valid > 0) {
+        put_byte(s, (Byte)s->bi_buf);
+    }
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+#ifdef DEBUG
+    s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+    deflate_state *s;
+    charf    *buf;    /* the input data */
+    unsigned len;     /* its length */
+    int      header;  /* true if block header must be written */
+{
+    bi_windup(s);        /* align on byte boundary */
+
+    if (header) {
+        put_short(s, (ush)len);
+        put_short(s, (ush)~len);
+#ifdef DEBUG
+        s->bits_sent += 2*16;
+#endif
+    }
+#ifdef DEBUG
+    s->bits_sent += (ulg)len<<3;
+#endif
+    while (len--) {
+        put_byte(s, *buf++);
+    }
+}
diff --git a/src/external/tng_io/external/zlib/trees.h b/src/external/tng_io/external/zlib/trees.h
new file mode 100644 (file)
index 0000000..d35639d
--- /dev/null
@@ -0,0 +1,128 @@
+/* header created automatically with -DGEN_TREES_H */
+
+local const ct_data static_ltree[L_CODES+2] = {
+{{ 12},{  8}}, {{140},{  8}}, {{ 76},{  8}}, {{204},{  8}}, {{ 44},{  8}},
+{{172},{  8}}, {{108},{  8}}, {{236},{  8}}, {{ 28},{  8}}, {{156},{  8}},
+{{ 92},{  8}}, {{220},{  8}}, {{ 60},{  8}}, {{188},{  8}}, {{124},{  8}},
+{{252},{  8}}, {{  2},{  8}}, {{130},{  8}}, {{ 66},{  8}}, {{194},{  8}},
+{{ 34},{  8}}, {{162},{  8}}, {{ 98},{  8}}, {{226},{  8}}, {{ 18},{  8}},
+{{146},{  8}}, {{ 82},{  8}}, {{210},{  8}}, {{ 50},{  8}}, {{178},{  8}},
+{{114},{  8}}, {{242},{  8}}, {{ 10},{  8}}, {{138},{  8}}, {{ 74},{  8}},
+{{202},{  8}}, {{ 42},{  8}}, {{170},{  8}}, {{106},{  8}}, {{234},{  8}},
+{{ 26},{  8}}, {{154},{  8}}, {{ 90},{  8}}, {{218},{  8}}, {{ 58},{  8}},
+{{186},{  8}}, {{122},{  8}}, {{250},{  8}}, {{  6},{  8}}, {{134},{  8}},
+{{ 70},{  8}}, {{198},{  8}}, {{ 38},{  8}}, {{166},{  8}}, {{102},{  8}},
+{{230},{  8}}, {{ 22},{  8}}, {{150},{  8}}, {{ 86},{  8}}, {{214},{  8}},
+{{ 54},{  8}}, {{182},{  8}}, {{118},{  8}}, {{246},{  8}}, {{ 14},{  8}},
+{{142},{  8}}, {{ 78},{  8}}, {{206},{  8}}, {{ 46},{  8}}, {{174},{  8}},
+{{110},{  8}}, {{238},{  8}}, {{ 30},{  8}}, {{158},{  8}}, {{ 94},{  8}},
+{{222},{  8}}, {{ 62},{  8}}, {{190},{  8}}, {{126},{  8}}, {{254},{  8}},
+{{  1},{  8}}, {{129},{  8}}, {{ 65},{  8}}, {{193},{  8}}, {{ 33},{  8}},
+{{161},{  8}}, {{ 97},{  8}}, {{225},{  8}}, {{ 17},{  8}}, {{145},{  8}},
+{{ 81},{  8}}, {{209},{  8}}, {{ 49},{  8}}, {{177},{  8}}, {{113},{  8}},
+{{241},{  8}}, {{  9},{  8}}, {{137},{  8}}, {{ 73},{  8}}, {{201},{  8}},
+{{ 41},{  8}}, {{169},{  8}}, {{105},{  8}}, {{233},{  8}}, {{ 25},{  8}},
+{{153},{  8}}, {{ 89},{  8}}, {{217},{  8}}, {{ 57},{  8}}, {{185},{  8}},
+{{121},{  8}}, {{249},{  8}}, {{  5},{  8}}, {{133},{  8}}, {{ 69},{  8}},
+{{197},{  8}}, {{ 37},{  8}}, {{165},{  8}}, {{101},{  8}}, {{229},{  8}},
+{{ 21},{  8}}, {{149},{  8}}, {{ 85},{  8}}, {{213},{  8}}, {{ 53},{  8}},
+{{181},{  8}}, {{117},{  8}}, {{245},{  8}}, {{ 13},{  8}}, {{141},{  8}},
+{{ 77},{  8}}, {{205},{  8}}, {{ 45},{  8}}, {{173},{  8}}, {{109},{  8}},
+{{237},{  8}}, {{ 29},{  8}}, {{157},{  8}}, {{ 93},{  8}}, {{221},{  8}},
+{{ 61},{  8}}, {{189},{  8}}, {{125},{  8}}, {{253},{  8}}, {{ 19},{  9}},
+{{275},{  9}}, {{147},{  9}}, {{403},{  9}}, {{ 83},{  9}}, {{339},{  9}},
+{{211},{  9}}, {{467},{  9}}, {{ 51},{  9}}, {{307},{  9}}, {{179},{  9}},
+{{435},{  9}}, {{115},{  9}}, {{371},{  9}}, {{243},{  9}}, {{499},{  9}},
+{{ 11},{  9}}, {{267},{  9}}, {{139},{  9}}, {{395},{  9}}, {{ 75},{  9}},
+{{331},{  9}}, {{203},{  9}}, {{459},{  9}}, {{ 43},{  9}}, {{299},{  9}},
+{{171},{  9}}, {{427},{  9}}, {{107},{  9}}, {{363},{  9}}, {{235},{  9}},
+{{491},{  9}}, {{ 27},{  9}}, {{283},{  9}}, {{155},{  9}}, {{411},{  9}},
+{{ 91},{  9}}, {{347},{  9}}, {{219},{  9}}, {{475},{  9}}, {{ 59},{  9}},
+{{315},{  9}}, {{187},{  9}}, {{443},{  9}}, {{123},{  9}}, {{379},{  9}},
+{{251},{  9}}, {{507},{  9}}, {{  7},{  9}}, {{263},{  9}}, {{135},{  9}},
+{{391},{  9}}, {{ 71},{  9}}, {{327},{  9}}, {{199},{  9}}, {{455},{  9}},
+{{ 39},{  9}}, {{295},{  9}}, {{167},{  9}}, {{423},{  9}}, {{103},{  9}},
+{{359},{  9}}, {{231},{  9}}, {{487},{  9}}, {{ 23},{  9}}, {{279},{  9}},
+{{151},{  9}}, {{407},{  9}}, {{ 87},{  9}}, {{343},{  9}}, {{215},{  9}},
+{{471},{  9}}, {{ 55},{  9}}, {{311},{  9}}, {{183},{  9}}, {{439},{  9}},
+{{119},{  9}}, {{375},{  9}}, {{247},{  9}}, {{503},{  9}}, {{ 15},{  9}},
+{{271},{  9}}, {{143},{  9}}, {{399},{  9}}, {{ 79},{  9}}, {{335},{  9}},
+{{207},{  9}}, {{463},{  9}}, {{ 47},{  9}}, {{303},{  9}}, {{175},{  9}},
+{{431},{  9}}, {{111},{  9}}, {{367},{  9}}, {{239},{  9}}, {{495},{  9}},
+{{ 31},{  9}}, {{287},{  9}}, {{159},{  9}}, {{415},{  9}}, {{ 95},{  9}},
+{{351},{  9}}, {{223},{  9}}, {{479},{  9}}, {{ 63},{  9}}, {{319},{  9}},
+{{191},{  9}}, {{447},{  9}}, {{127},{  9}}, {{383},{  9}}, {{255},{  9}},
+{{511},{  9}}, {{  0},{  7}}, {{ 64},{  7}}, {{ 32},{  7}}, {{ 96},{  7}},
+{{ 16},{  7}}, {{ 80},{  7}}, {{ 48},{  7}}, {{112},{  7}}, {{  8},{  7}},
+{{ 72},{  7}}, {{ 40},{  7}}, {{104},{  7}}, {{ 24},{  7}}, {{ 88},{  7}},
+{{ 56},{  7}}, {{120},{  7}}, {{  4},{  7}}, {{ 68},{  7}}, {{ 36},{  7}},
+{{100},{  7}}, {{ 20},{  7}}, {{ 84},{  7}}, {{ 52},{  7}}, {{116},{  7}},
+{{  3},{  8}}, {{131},{  8}}, {{ 67},{  8}}, {{195},{  8}}, {{ 35},{  8}},
+{{163},{  8}}, {{ 99},{  8}}, {{227},{  8}}
+};
+
+local const ct_data static_dtree[D_CODES] = {
+{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
+{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
+{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
+{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
+{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
+{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
+};
+
+const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {
+ 0,  1,  2,  3,  4,  4,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  8,
+ 8,  8,  8,  8,  9,  9,  9,  9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 10, 10, 10,
+10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  0,  0, 16, 17,
+18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+};
+
+const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {
+ 0,  1,  2,  3,  4,  5,  6,  7,  8,  8,  9,  9, 10, 10, 11, 11, 12, 12, 12, 12,
+13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+};
+
+local const int base_length[LENGTH_CODES] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+64, 80, 96, 112, 128, 160, 192, 224, 0
+};
+
+local const int base_dist[D_CODES] = {
+    0,     1,     2,     3,     4,     6,     8,    12,    16,    24,
+   32,    48,    64,    96,   128,   192,   256,   384,   512,   768,
+ 1024,  1536,  2048,  3072,  4096,  6144,  8192, 12288, 16384, 24576
+};
+
diff --git a/src/external/tng_io/external/zlib/uncompr.c b/src/external/tng_io/external/zlib/uncompr.c
new file mode 100644 (file)
index 0000000..242e949
--- /dev/null
@@ -0,0 +1,59 @@
+/* uncompr.c -- decompress a memory buffer
+ * Copyright (C) 1995-2003, 2010 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be large enough to hold the
+   entire uncompressed data. (The size of the uncompressed data must have
+   been saved previously by the compressor and transmitted to the decompressor
+   by some mechanism outside the scope of this compression library.)
+   Upon exit, destLen is the actual size of the compressed buffer.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+int ZEXPORT uncompress (dest, destLen, source, sourceLen)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+{
+    z_stream stream;
+    int err;
+
+    stream.next_in = (z_const Bytef *)source;
+    stream.avail_in = (uInt)sourceLen;
+    /* Check for source > 64K on 16-bit machine: */
+    if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+
+    stream.next_out = dest;
+    stream.avail_out = (uInt)*destLen;
+    if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+    stream.zalloc = (alloc_func)0;
+    stream.zfree = (free_func)0;
+
+    err = inflateInit(&stream);
+    if (err != Z_OK) return err;
+
+    err = inflate(&stream, Z_FINISH);
+    if (err != Z_STREAM_END) {
+        inflateEnd(&stream);
+        if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
+            return Z_DATA_ERROR;
+        return err;
+    }
+    *destLen = stream.total_out;
+
+    err = inflateEnd(&stream);
+    return err;
+}
diff --git a/src/external/tng_io/external/zlib/zconf.h b/src/external/tng_io/external/zlib/zconf.h
new file mode 100644 (file)
index 0000000..c90fb53
--- /dev/null
@@ -0,0 +1,367 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2013 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+#  define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+#  define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+#  define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+#  ifndef WIN32
+#    define WIN32
+#  endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+#  if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+#    ifndef SYS16BIT
+#      define SYS16BIT
+#    endif
+#  endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+#  define MAXSEG_64K
+#endif
+#ifdef MSDOS
+#  define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+#  ifndef STDC
+#    define STDC
+#  endif
+#  if __STDC_VERSION__ >= 199901L
+#    ifndef STDC99
+#      define STDC99
+#    endif
+#  endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+#  define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC)    /* iSeries (formerly AS/400). */
+#  define STDC
+#endif
+
+#ifndef STDC
+#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+#    define const       /* note: need a more gentle solution here */
+#  endif
+#endif
+
+#if defined(ZLIB_CONST) && !defined(z_const)
+#  define z_const const
+#else
+#  define z_const
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+#  define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  ifdef MAXSEG_64K
+#    define MAX_MEM_LEVEL 8
+#  else
+#    define MAX_MEM_LEVEL 9
+#  endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            (1 << (windowBits+2)) +  (1 << (memLevel+9))
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+#ifndef Z_ARG /* function prototypes for stdarg */
+#  if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#    define Z_ARG(args)  args
+#  else
+#    define Z_ARG(args)  ()
+#  endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+#  if defined(M_I86SM) || defined(M_I86MM)
+     /* MSC small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef _MSC_VER
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#  if (defined(__SMALL__) || defined(__MEDIUM__))
+     /* Turbo C small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef __BORLANDC__
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+   /* If building or using zlib as a DLL, define ZLIB_DLL.
+    * This is not mandatory, but it offers a little performance increase.
+    */
+#  ifdef ZLIB_DLL
+#    if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+#      ifdef ZLIB_INTERNAL
+#        define ZEXTERN extern __declspec(dllexport)
+#      else
+#        define ZEXTERN extern __declspec(dllimport)
+#      endif
+#    endif
+#  endif  /* ZLIB_DLL */
+   /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+    * define ZLIB_WINAPI.
+    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+    */
+#  ifdef ZLIB_WINAPI
+#    ifdef FAR
+#      undef FAR
+#    endif
+#    include <windows.h>
+     /* No need for _export, use ZLIB.DEF instead. */
+     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+#    define ZEXPORT WINAPI
+#    ifdef WIN32
+#      define ZEXPORTVA WINAPIV
+#    else
+#      define ZEXPORTVA FAR CDECL
+#    endif
+#  endif
+#endif
+
+#if defined (__BEOS__)
+#  ifdef ZLIB_DLL
+#    ifdef ZLIB_INTERNAL
+#      define ZEXPORT   __declspec(dllexport)
+#      define ZEXPORTVA __declspec(dllexport)
+#    else
+#      define ZEXPORT   __declspec(dllimport)
+#      define ZEXPORTVA __declspec(dllimport)
+#    endif
+#  endif
+#endif
+
+#ifndef ZEXTERN
+#  define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+#  define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+#  define ZEXPORTVA
+#endif
+
+#ifndef FAR
+#  define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char  Byte;  /* 8 bits */
+#endif
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+#  define Bytef Byte FAR
+#else
+   typedef Byte  FAR Bytef;
+#endif
+typedef char  FAR charf;
+typedef int   FAR intf;
+typedef uInt  FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+   typedef void const *voidpc;
+   typedef void FAR   *voidpf;
+   typedef void       *voidp;
+#else
+   typedef Byte const *voidpc;
+   typedef Byte FAR   *voidpf;
+   typedef Byte       *voidp;
+#endif
+
+#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)
+#  include <limits.h>
+#  if (UINT_MAX == 0xffffffffUL)
+#    define Z_U4 unsigned
+#  elif (ULONG_MAX == 0xffffffffUL)
+#    define Z_U4 unsigned long
+#  elif (USHRT_MAX == 0xffffffffUL)
+#    define Z_U4 unsigned short
+#  endif
+#endif
+
+#ifdef Z_U4
+   typedef Z_U4 z_crc_t;
+#else
+   typedef unsigned long z_crc_t;
+#endif
+
+#ifdef HAVE_UNISTD_H    /* may be set to #if 1 by ./configure */
+#  define Z_HAVE_UNISTD_H
+#endif
+
+#ifdef HAVE_STDARG_H    /* may be set to #if 1 by ./configure */
+#  define Z_HAVE_STDARG_H
+#endif
+
+#ifdef STDC
+#  ifndef Z_SOLO
+#    include <sys/types.h>      /* for off_t */
+#  endif
+#endif
+
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#  ifndef Z_SOLO
+#    include <stdarg.h>         /* for va_list */
+#  endif
+#endif
+
+#ifdef _WIN32
+#  ifndef Z_SOLO
+#    include <stddef.h>         /* for wchar_t */
+#  endif
+#endif
+
+/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
+ * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
+ * though the former does not conform to the LFS document), but considering
+ * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
+ * equivalently requesting no 64-bit operations
+ */
+#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1
+#  undef _LARGEFILE64_SOURCE
+#endif
+
+#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
+#  define Z_HAVE_UNISTD_H
+#endif
+#ifndef Z_SOLO
+#  if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
+#    include <unistd.h>         /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
+#    ifdef VMS
+#      include <unixio.h>       /* for off_t */
+#    endif
+#    ifndef z_off_t
+#      define z_off_t off_t
+#    endif
+#  endif
+#endif
+
+#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0
+#  define Z_LFS64
+#endif
+
+#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)
+#  define Z_LARGE64
+#endif
+
+#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)
+#  define Z_WANT64
+#endif
+
+#if !defined(SEEK_SET) && !defined(Z_SOLO)
+#  define SEEK_SET        0       /* Seek from beginning of file.  */
+#  define SEEK_CUR        1       /* Seek from current position.  */
+#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
+#endif
+
+#ifndef z_off_t
+#  define z_off_t long
+#endif
+
+#if !defined(_WIN32) && defined(Z_LARGE64)
+#  define z_off64_t off64_t
+#else
+#  if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)
+#    define z_off64_t __int64
+#  else
+#    define z_off64_t z_off_t
+#  endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+  #pragma map(deflateInit_,"DEIN")
+  #pragma map(deflateInit2_,"DEIN2")
+  #pragma map(deflateEnd,"DEEND")
+  #pragma map(deflateBound,"DEBND")
+  #pragma map(inflateInit_,"ININ")
+  #pragma map(inflateInit2_,"ININ2")
+  #pragma map(inflateEnd,"INEND")
+  #pragma map(inflateSync,"INSY")
+  #pragma map(inflateSetDictionary,"INSEDI")
+  #pragma map(compressBound,"CMBND")
+  #pragma map(inflate_table,"INTABL")
+  #pragma map(inflate_fast,"INFA")
+  #pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
diff --git a/src/external/tng_io/external/zlib/zlib.h b/src/external/tng_io/external/zlib/zlib.h
new file mode 100644 (file)
index 0000000..565d0ed
--- /dev/null
@@ -0,0 +1,1769 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.2.8, April 28th, 2013
+
+  Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup@gzip.org          madler@alumni.caltech.edu
+
+
+  The data format used by the zlib library is described by RFCs (Request for
+  Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950
+  (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).
+*/
+
+#ifndef ZLIB_H
+#define ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.8"
+#define ZLIB_VERNUM 0x1280
+#define ZLIB_VER_MAJOR 1
+#define ZLIB_VER_MINOR 2
+#define ZLIB_VER_REVISION 8
+#define ZLIB_VER_SUBREVISION 0
+
+/*
+    The 'zlib' compression library provides in-memory compression and
+  decompression functions, including integrity checks of the uncompressed data.
+  This version of the library supports only one compression method (deflation)
+  but other algorithms will be added later and will have the same stream
+  interface.
+
+    Compression can be done in a single step if the buffers are large enough,
+  or can be done by repeated calls of the compression function.  In the latter
+  case, the application must provide more input and/or consume the output
+  (providing more output space) before each call.
+
+    The compressed data format used by default by the in-memory functions is
+  the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+  around a deflate stream, which is itself documented in RFC 1951.
+
+    The library also supports reading and writing files in gzip (.gz) format
+  with an interface similar to that of stdio using the functions that start
+  with "gz".  The gzip format is different from the zlib format.  gzip is a
+  gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
+
+    This library can optionally read and write gzip streams in memory as well.
+
+    The zlib format was designed to be compact and fast for use in memory
+  and on communications channels.  The gzip format was designed for single-
+  file compression on file systems, has a larger header than zlib to maintain
+  directory information, and uses a different, slower check method than zlib.
+
+    The library does not install any signal handler.  The decoder checks
+  the consistency of the compressed data, so the library should never crash
+  even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+    z_const Bytef *next_in;     /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total number of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte should be put there */
+    uInt     avail_out; /* remaining free space at next_out */
+    uLong    total_out; /* total number of bytes output so far */
+
+    z_const char *msg;  /* last error message, NULL if no error */
+    struct internal_state FAR *state; /* not visible by applications */
+
+    alloc_func zalloc;  /* used to allocate the internal state */
+    free_func  zfree;   /* used to free the internal state */
+    voidpf     opaque;  /* private data object passed to zalloc and zfree */
+
+    int     data_type;  /* best guess about the data type: binary or text */
+    uLong   adler;      /* adler32 value of the uncompressed data */
+    uLong   reserved;   /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+     gzip header information passed to and from zlib routines.  See RFC 1952
+  for more details on the meanings of these fields.
+*/
+typedef struct gz_header_s {
+    int     text;       /* true if compressed data believed to be text */
+    uLong   time;       /* modification time */
+    int     xflags;     /* extra flags (not used when writing a gzip file) */
+    int     os;         /* operating system */
+    Bytef   *extra;     /* pointer to extra field or Z_NULL if none */
+    uInt    extra_len;  /* extra field length (valid if extra != Z_NULL) */
+    uInt    extra_max;  /* space at extra (only when reading header) */
+    Bytef   *name;      /* pointer to zero-terminated file name or Z_NULL */
+    uInt    name_max;   /* space at name (only when reading header) */
+    Bytef   *comment;   /* pointer to zero-terminated comment or Z_NULL */
+    uInt    comm_max;   /* space at comment (only when reading header) */
+    int     hcrc;       /* true if there was or will be a header crc */
+    int     done;       /* true when done reading gzip header (not used
+                           when writing a gzip file) */
+} gz_header;
+
+typedef gz_header FAR *gz_headerp;
+
+/*
+     The application must update next_in and avail_in when avail_in has dropped
+   to zero.  It must update next_out and avail_out when avail_out has dropped
+   to zero.  The application must initialize zalloc, zfree and opaque before
+   calling the init function.  All other fields are set by the compression
+   library and must not be updated by the application.
+
+     The opaque value provided by the application will be passed as the first
+   parameter for calls of zalloc and zfree.  This can be useful for custom
+   memory management.  The compression library attaches no meaning to the
+   opaque value.
+
+     zalloc must return Z_NULL if there is not enough memory for the object.
+   If zlib is used in a multi-threaded application, zalloc and zfree must be
+   thread safe.
+
+     On 16-bit systems, the functions zalloc and zfree must be able to allocate
+   exactly 65536 bytes, but will not be required to allocate more than this if
+   the symbol MAXSEG_64K is defined (see zconf.h).  WARNING: On MSDOS, pointers
+   returned by zalloc for objects of exactly 65536 bytes *must* have their
+   offset normalized to zero.  The default allocation function provided by this
+   library ensures this (see zutil.c).  To reduce memory requirements and avoid
+   any allocation of 64K objects, at the expense of compression ratio, compile
+   the library with -DMAX_WBITS=14 (see zconf.h).
+
+     The fields total_in and total_out can be used for statistics or progress
+   reports.  After compression, total_in holds the total size of the
+   uncompressed data and may be saved for use in the decompressor (particularly
+   if the decompressor wants to decompress everything in a single step).
+*/
+
+                        /* constants */
+
+#define Z_NO_FLUSH      0
+#define Z_PARTIAL_FLUSH 1
+#define Z_SYNC_FLUSH    2
+#define Z_FULL_FLUSH    3
+#define Z_FINISH        4
+#define Z_BLOCK         5
+#define Z_TREES         6
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_NEED_DICT     2
+#define Z_ERRNO        (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative values
+ * are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION         0
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1)
+/* compression levels */
+
+#define Z_FILTERED            1
+#define Z_HUFFMAN_ONLY        2
+#define Z_RLE                 3
+#define Z_FIXED               4
+#define Z_DEFAULT_STRATEGY    0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY   0
+#define Z_TEXT     1
+#define Z_ASCII    Z_TEXT   /* for compatibility with 1.2.2 and earlier */
+#define Z_UNKNOWN  2
+/* Possible values of the data_type field (though see inflate()) */
+
+#define Z_DEFLATED   8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+
+                        /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+   If the first character differs, the library code actually used is not
+   compatible with the zlib.h header file used by the application.  This check
+   is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+     Initializes the internal stream state for compression.  The fields
+   zalloc, zfree and opaque must be initialized before by the caller.  If
+   zalloc and zfree are set to Z_NULL, deflateInit updates them to use default
+   allocation functions.
+
+     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+   1 gives best speed, 9 gives best compression, 0 gives no compression at all
+   (the input data is simply copied a block at a time).  Z_DEFAULT_COMPRESSION
+   requests a default compromise between speed and compression (currently
+   equivalent to level 6).
+
+     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if level is not a valid compression level, or
+   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+   with the version assumed by the caller (ZLIB_VERSION).  msg is set to null
+   if there is no error message.  deflateInit does not perform any compression:
+   this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+    deflate compresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full.  It may introduce
+  some output latency (reading input without producing any output) except when
+  forced to flush.
+
+    The detailed semantics are as follows.  deflate performs one or both of the
+  following actions:
+
+  - Compress more input starting at next_in and update next_in and avail_in
+    accordingly.  If not all input can be processed (because there is not
+    enough room in the output buffer), next_in and avail_in are updated and
+    processing will resume at this point for the next call of deflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  This action is forced if the parameter flush is non zero.
+    Forcing flush frequently degrades the compression ratio, so this parameter
+    should be set only when necessary (in interactive applications).  Some
+    output may be provided even if flush is not set.
+
+    Before the call of deflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming more
+  output, and updating avail_in or avail_out accordingly; avail_out should
+  never be zero before the call.  The application can consume the compressed
+  output when it wants, for example when the output buffer is full (avail_out
+  == 0), or after each call of deflate().  If deflate returns Z_OK and with
+  zero avail_out, it must be called again after making room in the output
+  buffer because there might be more output pending.
+
+    Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
+  decide how much data to accumulate before producing output, in order to
+  maximize compression.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+  flushed to the output buffer and the output is aligned on a byte boundary, so
+  that the decompressor can get all input data available so far.  (In
+  particular avail_in is zero after the call if enough output space has been
+  provided before the call.) Flushing may degrade compression for some
+  compression algorithms and so it should be used only when necessary.  This
+  completes the current deflate block and follows it with an empty stored block
+  that is three bits plus filler bits to the next byte, followed by four bytes
+  (00 00 ff ff).
+
+    If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the
+  output buffer, but the output is not aligned to a byte boundary.  All of the
+  input data so far will be available to the decompressor, as for Z_SYNC_FLUSH.
+  This completes the current deflate block and follows it with an empty fixed
+  codes block that is 10 bits long.  This assures that enough bytes are output
+  in order for the decompressor to finish the block before the empty fixed code
+  block.
+
+    If flush is set to Z_BLOCK, a deflate block is completed and emitted, as
+  for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to
+  seven bits of the current block are held to be written as the next byte after
+  the next deflate block is completed.  In this case, the decompressor may not
+  be provided enough bits at this point in order to complete decompression of
+  the data provided so far to the compressor.  It may need to wait for the next
+  block to be emitted.  This is for advanced applications that need to control
+  the emission of deflate blocks.
+
+    If flush is set to Z_FULL_FLUSH, all output is flushed as with
+  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+  restart from this point if previous compressed data has been damaged or if
+  random access is desired.  Using Z_FULL_FLUSH too often can seriously degrade
+  compression.
+
+    If deflate returns with avail_out == 0, this function must be called again
+  with the same value of the flush parameter and more output space (updated
+  avail_out), until the flush is complete (deflate returns with non-zero
+  avail_out).  In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
+  avail_out is greater than six to avoid repeated flush markers due to
+  avail_out == 0 on return.
+
+    If the parameter flush is set to Z_FINISH, pending input is processed,
+  pending output is flushed and deflate returns with Z_STREAM_END if there was
+  enough output space; if deflate returns with Z_OK, this function must be
+  called again with Z_FINISH and more output space (updated avail_out) but no
+  more input data, until it returns with Z_STREAM_END or an error.  After
+  deflate has returned Z_STREAM_END, the only possible operations on the stream
+  are deflateReset or deflateEnd.
+
+    Z_FINISH can be used immediately after deflateInit if all the compression
+  is to be done in a single step.  In this case, avail_out must be at least the
+  value returned by deflateBound (see below).  Then deflate is guaranteed to
+  return Z_STREAM_END.  If not enough output space is provided, deflate will
+  not return Z_STREAM_END, and it must be called again as described above.
+
+    deflate() sets strm->adler to the adler32 checksum of all input read
+  so far (that is, total_in bytes).
+
+    deflate() may update strm->data_type if it can make a good guess about
+  the input data type (Z_BINARY or Z_TEXT).  In doubt, the data is considered
+  binary.  This field is only for information purposes and does not affect the
+  compression algorithm in any manner.
+
+    deflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if all input has been
+  consumed and all output has been produced (only when flush is set to
+  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+  if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible
+  (for example avail_in or avail_out was zero).  Note that Z_BUF_ERROR is not
+  fatal, and deflate() can be called again with more input and more output
+  space to continue compressing.
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any pending
+   output.
+
+     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+   prematurely (some input or output was discarded).  In the error case, msg
+   may be set but then points to a static string (which must not be
+   deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+     Initializes the internal stream state for decompression.  The fields
+   next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+   the caller.  If next_in is not Z_NULL and avail_in is large enough (the
+   exact value depends on the compression method), inflateInit determines the
+   compression method from the zlib header and allocates all data structures
+   accordingly; otherwise the allocation will be deferred to the first call of
+   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+   use default allocation functions.
+
+     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+   version assumed by the caller, or Z_STREAM_ERROR if the parameters are
+   invalid, such as a null pointer to the structure.  msg is set to null if
+   there is no error message.  inflateInit does not perform any decompression
+   apart from possibly reading the zlib header if present: actual decompression
+   will be done by inflate().  (So next_in and avail_in may be modified, but
+   next_out and avail_out are unused and unchanged.) The current implementation
+   of inflateInit() does not process any header information -- that is deferred
+   until inflate() is called.
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+    inflate decompresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full.  It may introduce
+  some output latency (reading input without producing any output) except when
+  forced to flush.
+
+  The detailed semantics are as follows.  inflate performs one or both of the
+  following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly.  If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing will
+    resume at this point for the next call of inflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  inflate() provides as much output as possible, until there is
+    no more input data or no more space in the output buffer (see below about
+    the flush parameter).
+
+    Before the call of inflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming more
+  output, and updating the next_* and avail_* values accordingly.  The
+  application can consume the uncompressed output when it wants, for example
+  when the output buffer is full (avail_out == 0), or after each call of
+  inflate().  If inflate returns Z_OK and with zero avail_out, it must be
+  called again after making room in the output buffer because there might be
+  more output pending.
+
+    The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH,
+  Z_BLOCK, or Z_TREES.  Z_SYNC_FLUSH requests that inflate() flush as much
+  output as possible to the output buffer.  Z_BLOCK requests that inflate()
+  stop if and when it gets to the next deflate block boundary.  When decoding
+  the zlib or gzip format, this will cause inflate() to return immediately
+  after the header and before the first block.  When doing a raw inflate,
+  inflate() will go ahead and process the first block, and will return when it
+  gets to the end of that block, or when it runs out of data.
+
+    The Z_BLOCK option assists in appending to or combining deflate streams.
+  Also to assist in this, on return inflate() will set strm->data_type to the
+  number of unused bits in the last byte taken from strm->next_in, plus 64 if
+  inflate() is currently decoding the last block in the deflate stream, plus
+  128 if inflate() returned immediately after decoding an end-of-block code or
+  decoding the complete header up to just before the first byte of the deflate
+  stream.  The end-of-block will not be indicated until all of the uncompressed
+  data from that block has been written to strm->next_out.  The number of
+  unused bits may in general be greater than seven, except when bit 7 of
+  data_type is set, in which case the number of unused bits will be less than
+  eight.  data_type is set as noted here every time inflate() returns for all
+  flush options, and so can be used to determine the amount of currently
+  consumed input in bits.
+
+    The Z_TREES option behaves as Z_BLOCK does, but it also returns when the
+  end of each deflate block header is reached, before any actual data in that
+  block is decoded.  This allows the caller to determine the length of the
+  deflate block header for later use in random access within a deflate block.
+  256 is added to the value of strm->data_type when inflate() returns
+  immediately after reaching the end of the deflate block header.
+
+    inflate() should normally be called until it returns Z_STREAM_END or an
+  error.  However if all decompression is to be performed in a single step (a
+  single call of inflate), the parameter flush should be set to Z_FINISH.  In
+  this case all pending input is processed and all pending output is flushed;
+  avail_out must be large enough to hold all of the uncompressed data for the
+  operation to complete.  (The size of the uncompressed data may have been
+  saved by the compressor for this purpose.) The use of Z_FINISH is not
+  required to perform an inflation in one step.  However it may be used to
+  inform inflate that a faster approach can be used for the single inflate()
+  call.  Z_FINISH also informs inflate to not maintain a sliding window if the
+  stream completes, which reduces inflate's memory footprint.  If the stream
+  does not complete, either because not all of the stream is provided or not
+  enough output space is provided, then a sliding window will be allocated and
+  inflate() can be called again to continue the operation as if Z_NO_FLUSH had
+  been used.
+
+     In this implementation, inflate() always flushes as much output as
+  possible to the output buffer, and always uses the faster approach on the
+  first call.  So the effects of the flush parameter in this implementation are
+  on the return value of inflate() as noted below, when inflate() returns early
+  when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of
+  memory for a sliding window when Z_FINISH is used.
+
+     If a preset dictionary is needed after this call (see inflateSetDictionary
+  below), inflate sets strm->adler to the Adler-32 checksum of the dictionary
+  chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+  strm->adler to the Adler-32 checksum of all output produced so far (that is,
+  total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+  below.  At the end of the stream, inflate() checks that its computed adler32
+  checksum is equal to that saved by the compressor and returns Z_STREAM_END
+  only if the checksum is correct.
+
+    inflate() can decompress and check either zlib-wrapped or gzip-wrapped
+  deflate data.  The header type is detected automatically, if requested when
+  initializing with inflateInit2().  Any information contained in the gzip
+  header is not retained, so applications that need that information should
+  instead use raw inflate, see inflateInit2() below, or inflateBack() and
+  perform their own processing of the gzip header and trailer.  When processing
+  gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output
+  producted so far.  The CRC-32 is checked against the gzip trailer.
+
+    inflate() returns Z_OK if some progress has been made (more input processed
+  or more output produced), Z_STREAM_END if the end of the compressed data has
+  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+  corrupted (input stream not conforming to the zlib format or incorrect check
+  value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+  next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory,
+  Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+  output buffer when Z_FINISH is used.  Note that Z_BUF_ERROR is not fatal, and
+  inflate() can be called again with more input and more output space to
+  continue decompressing.  If Z_DATA_ERROR is returned, the application may
+  then call inflateSync() to look for a good compression block if a partial
+  recovery of the data is desired.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any pending
+   output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent.  In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+*/
+
+
+                        /* Advanced functions */
+
+/*
+    The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+                                     int  level,
+                                     int  method,
+                                     int  windowBits,
+                                     int  memLevel,
+                                     int  strategy));
+
+     This is another version of deflateInit with more compression options.  The
+   fields next_in, zalloc, zfree and opaque must be initialized before by the
+   caller.
+
+     The method parameter is the compression method.  It must be Z_DEFLATED in
+   this version of the library.
+
+     The windowBits parameter is the base two logarithm of the window size
+   (the size of the history buffer).  It should be in the range 8..15 for this
+   version of the library.  Larger values of this parameter result in better
+   compression at the expense of memory usage.  The default value is 15 if
+   deflateInit is used instead.
+
+     windowBits can also be -8..-15 for raw deflate.  In this case, -windowBits
+   determines the window size.  deflate() will then generate raw deflate data
+   with no zlib header or trailer, and will not compute an adler32 check value.
+
+     windowBits can also be greater than 15 for optional gzip encoding.  Add
+   16 to windowBits to write a simple gzip header and trailer around the
+   compressed data instead of a zlib wrapper.  The gzip header will have no
+   file name, no extra data, no comment, no modification time (set to zero), no
+   header crc, and the operating system will be set to 255 (unknown).  If a
+   gzip stream is being written, strm->adler is a crc32 instead of an adler32.
+
+     The memLevel parameter specifies how much memory should be allocated
+   for the internal compression state.  memLevel=1 uses minimum memory but is
+   slow and reduces compression ratio; memLevel=9 uses maximum memory for
+   optimal speed.  The default value is 8.  See zconf.h for total memory usage
+   as a function of windowBits and memLevel.
+
+     The strategy parameter is used to tune the compression algorithm.  Use the
+   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+   filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
+   string match), or Z_RLE to limit match distances to one (run-length
+   encoding).  Filtered data consists mostly of small values with a somewhat
+   random distribution.  In this case, the compression algorithm is tuned to
+   compress them better.  The effect of Z_FILTERED is to force more Huffman
+   coding and less string matching; it is somewhat intermediate between
+   Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY.  Z_RLE is designed to be almost as
+   fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data.  The
+   strategy parameter only affects the compression ratio but not the
+   correctness of the compressed output even if it is not set appropriately.
+   Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler
+   decoder for special applications.
+
+     deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid
+   method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is
+   incompatible with the version assumed by the caller (ZLIB_VERSION).  msg is
+   set to null if there is no error message.  deflateInit2 does not perform any
+   compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the compression dictionary from the given byte sequence
+   without producing any compressed output.  When using the zlib format, this
+   function must be called immediately after deflateInit, deflateInit2 or
+   deflateReset, and before any call of deflate.  When doing raw deflate, this
+   function must be called either before any call of deflate, or immediately
+   after the completion of a deflate block, i.e. after all input has been
+   consumed and all output has been delivered when using any of the flush
+   options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH.  The
+   compressor and decompressor must use exactly the same dictionary (see
+   inflateSetDictionary).
+
+     The dictionary should consist of strings (byte sequences) that are likely
+   to be encountered later in the data to be compressed, with the most commonly
+   used strings preferably put towards the end of the dictionary.  Using a
+   dictionary is most useful when the data to be compressed is short and can be
+   predicted with good accuracy; the data can then be compressed better than
+   with the default empty dictionary.
+
+     Depending on the size of the compression data structures selected by
+   deflateInit or deflateInit2, a part of the dictionary may in effect be
+   discarded, for example if the dictionary is larger than the window size
+   provided in deflateInit or deflateInit2.  Thus the strings most likely to be
+   useful should be put at the end of the dictionary, not at the front.  In
+   addition, the current implementation of deflate will use at most the window
+   size minus 262 bytes of the provided dictionary.
+
+     Upon return of this function, strm->adler is set to the adler32 value
+   of the dictionary; the decompressor may later use this value to determine
+   which dictionary has been used by the compressor.  (The adler32 value
+   applies to the whole dictionary even if only a subset of the dictionary is
+   actually used by the compressor.) If a raw deflate was requested, then the
+   adler32 value is not computed and strm->adler is not set.
+
+     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is
+   inconsistent (for example if deflate has already been called for this stream
+   or if not at a block boundary for raw deflate).  deflateSetDictionary does
+   not perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+                                    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when several compression strategies will be
+   tried, for example when there are several ways of pre-processing the input
+   data with a filter.  The streams that will be discarded should then be freed
+   by calling deflateEnd.  Note that deflateCopy duplicates the internal
+   compression state which can be quite large, so this strategy is slow and can
+   consume lots of memory.
+
+     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being Z_NULL).  msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to deflateEnd followed by deflateInit,
+   but does not free and reallocate all the internal compression state.  The
+   stream will keep the same compression level and any other attributes that
+   may have been set by deflateInit2.
+
+     deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being Z_NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+                                      int level,
+                                      int strategy));
+/*
+     Dynamically update the compression level and compression strategy.  The
+   interpretation of level and strategy is as in deflateInit2.  This can be
+   used to switch between compression and straight copy of the input data, or
+   to switch to a different kind of input data requiring a different strategy.
+   If the compression level is changed, the input available so far is
+   compressed with the old level (and may be flushed); the new level will take
+   effect only at the next call of deflate().
+
+     Before the call of deflateParams, the stream state must be set as for
+   a call of deflate(), since the currently available input may have to be
+   compressed and flushed.  In particular, strm->avail_out must be non-zero.
+
+     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if
+   strm->avail_out was zero.
+*/
+
+ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
+                                    int good_length,
+                                    int max_lazy,
+                                    int nice_length,
+                                    int max_chain));
+/*
+     Fine tune deflate's internal compression parameters.  This should only be
+   used by someone who understands the algorithm used by zlib's deflate for
+   searching for the best matching string, and even then only by the most
+   fanatic optimizer trying to squeeze out the last compressed bit for their
+   specific input data.  Read the deflate.c source code for the meaning of the
+   max_lazy, good_length, nice_length, and max_chain parameters.
+
+     deflateTune() can be called after deflateInit() or deflateInit2(), and
+   returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
+ */
+
+ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
+                                       uLong sourceLen));
+/*
+     deflateBound() returns an upper bound on the compressed size after
+   deflation of sourceLen bytes.  It must be called after deflateInit() or
+   deflateInit2(), and after deflateSetHeader(), if used.  This would be used
+   to allocate an output buffer for deflation in a single pass, and so would be
+   called before deflate().  If that first deflate() call is provided the
+   sourceLen input bytes, an output buffer allocated to the size returned by
+   deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed
+   to return Z_STREAM_END.  Note that it is possible for the compressed size to
+   be larger than the value returned by deflateBound() if flush options other
+   than Z_FINISH or Z_NO_FLUSH are used.
+*/
+
+ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm,
+                                       unsigned *pending,
+                                       int *bits));
+/*
+     deflatePending() returns the number of bytes and bits of output that have
+   been generated, but not yet provided in the available output.  The bytes not
+   provided would be due to the available output space having being consumed.
+   The number of bits of output not provided are between 0 and 7, where they
+   await more bits to join them in order to fill out a full byte.  If pending
+   or bits are Z_NULL, then those values are not set.
+
+     deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+ */
+
+ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
+                                     int bits,
+                                     int value));
+/*
+     deflatePrime() inserts bits in the deflate output stream.  The intent
+   is that this function is used to start off the deflate output with the bits
+   leftover from a previous deflate stream when appending to it.  As such, this
+   function can only be used for raw deflate, and must be used before the first
+   deflate() call after a deflateInit2() or deflateReset().  bits must be less
+   than or equal to 16, and that many of the least significant bits of value
+   will be inserted in the output.
+
+     deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough
+   room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the
+   source stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
+                                         gz_headerp head));
+/*
+     deflateSetHeader() provides gzip header information for when a gzip
+   stream is requested by deflateInit2().  deflateSetHeader() may be called
+   after deflateInit2() or deflateReset() and before the first call of
+   deflate().  The text, time, os, extra field, name, and comment information
+   in the provided gz_header structure are written to the gzip header (xflag is
+   ignored -- the extra flags are set according to the compression level).  The
+   caller must assure that, if not Z_NULL, name and comment are terminated with
+   a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
+   available there.  If hcrc is true, a gzip header crc is included.  Note that
+   the current versions of the command-line version of gzip (up through version
+   1.3.x) do not support header crc's, and will report that it is a "multi-part
+   gzip file" and give up.
+
+     If deflateSetHeader is not used, the default gzip header has text false,
+   the time set to zero, and os set to 255, with no extra, name, or comment
+   fields.  The gzip header is returned to the default state by deflateReset().
+
+     deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+                                     int  windowBits));
+
+     This is another version of inflateInit with an extra parameter.  The
+   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+   before by the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library.  The default value is 15 if inflateInit is used
+   instead.  windowBits must be greater than or equal to the windowBits value
+   provided to deflateInit2() while compressing, or it must be equal to 15 if
+   deflateInit2() was not used.  If a compressed stream with a larger window
+   size is given as input, inflate() will return with the error code
+   Z_DATA_ERROR instead of trying to allocate a larger window.
+
+     windowBits can also be zero to request that inflate use the window size in
+   the zlib header of the compressed stream.
+
+     windowBits can also be -8..-15 for raw inflate.  In this case, -windowBits
+   determines the window size.  inflate() will then process raw deflate data,
+   not looking for a zlib or gzip header, not generating a check value, and not
+   looking for any check values for comparison at the end of the stream.  This
+   is for use with other formats that use the deflate compressed data format
+   such as zip.  Those formats provide their own check values.  If a custom
+   format is developed using the raw deflate format for compressed data, it is
+   recommended that a check value such as an adler32 or a crc32 be applied to
+   the uncompressed data as is done in the zlib, gzip, and zip formats.  For
+   most applications, the zlib format should be used as is.  Note that comments
+   above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+     windowBits can also be greater than 15 for optional gzip decoding.  Add
+   32 to windowBits to enable zlib and gzip decoding with automatic header
+   detection, or add 16 to decode only the gzip format (the zlib format will
+   return a Z_DATA_ERROR).  If a gzip stream is being decoded, strm->adler is a
+   crc32 instead of an adler32.
+
+     inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+   version assumed by the caller, or Z_STREAM_ERROR if the parameters are
+   invalid, such as a null pointer to the structure.  msg is set to null if
+   there is no error message.  inflateInit2 does not perform any decompression
+   apart from possibly reading the zlib header if present: actual decompression
+   will be done by inflate().  (So next_in and avail_in may be modified, but
+   next_out and avail_out are unused and unchanged.) The current implementation
+   of inflateInit2() does not process any header information -- that is
+   deferred until inflate() is called.
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the decompression dictionary from the given uncompressed byte
+   sequence.  This function must be called immediately after a call of inflate,
+   if that call returned Z_NEED_DICT.  The dictionary chosen by the compressor
+   can be determined from the adler32 value returned by that call of inflate.
+   The compressor and decompressor must use exactly the same dictionary (see
+   deflateSetDictionary).  For raw inflate, this function can be called at any
+   time to set the dictionary.  If the provided dictionary is smaller than the
+   window and there is already data in the window, then the provided dictionary
+   will amend what's there.  The application must insure that the dictionary
+   that was used for compression is provided.
+
+     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is
+   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+   expected one (incorrect adler32 value).  inflateSetDictionary does not
+   perform any decompression: this will be done by subsequent calls of
+   inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm,
+                                             Bytef *dictionary,
+                                             uInt  *dictLength));
+/*
+     Returns the sliding dictionary being maintained by inflate.  dictLength is
+   set to the number of bytes in the dictionary, and that many bytes are copied
+   to dictionary.  dictionary must have enough space, where 32768 bytes is
+   always enough.  If inflateGetDictionary() is called with dictionary equal to
+   Z_NULL, then only the dictionary length is returned, and nothing is copied.
+   Similary, if dictLength is Z_NULL, then it is not set.
+
+     inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the
+   stream state is inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+     Skips invalid compressed data until a possible full flush point (see above
+   for the description of deflate with Z_FULL_FLUSH) can be found, or until all
+   available input is skipped.  No output is provided.
+
+     inflateSync searches for a 00 00 FF FF pattern in the compressed data.
+   All full flush points have this pattern, but not all occurrences of this
+   pattern are full flush points.
+
+     inflateSync returns Z_OK if a possible full flush point has been found,
+   Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point
+   has been found, or Z_STREAM_ERROR if the stream structure was inconsistent.
+   In the success case, the application may save the current current value of
+   total_in which indicates where valid compressed data was found.  In the
+   error case, the application may repeatedly call inflateSync, providing more
+   input each time, until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
+                                    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when randomly accessing a large stream.  The
+   first pass through the stream can periodically record the inflate state,
+   allowing restarting inflate at those points when randomly accessing the
+   stream.
+
+     inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being Z_NULL).  msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all the internal decompression state.  The
+   stream will keep attributes that may have been set by inflateInit2.
+
+     inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being Z_NULL).
+*/
+
+ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm,
+                                      int windowBits));
+/*
+     This function is the same as inflateReset, but it also permits changing
+   the wrap and window size requests.  The windowBits parameter is interpreted
+   the same as it is for inflateInit2.
+
+     inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being Z_NULL), or if
+   the windowBits parameter is invalid.
+*/
+
+ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
+                                     int bits,
+                                     int value));
+/*
+     This function inserts bits in the inflate input stream.  The intent is
+   that this function is used to start inflating at a bit position in the
+   middle of a byte.  The provided bits will be used before any bytes are used
+   from next_in.  This function should only be used with raw inflate, and
+   should be used before the first inflate() call after inflateInit2() or
+   inflateReset().  bits must be less than or equal to 16, and that many of the
+   least significant bits of value will be inserted in the input.
+
+     If bits is negative, then the input stream bit buffer is emptied.  Then
+   inflatePrime() can be called again to put bits in the buffer.  This is used
+   to clear out bits leftover after feeding inflate a block description prior
+   to feeding inflate codes.
+
+     inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm));
+/*
+     This function returns two values, one in the lower 16 bits of the return
+   value, and the other in the remaining upper bits, obtained by shifting the
+   return value down 16 bits.  If the upper value is -1 and the lower value is
+   zero, then inflate() is currently decoding information outside of a block.
+   If the upper value is -1 and the lower value is non-zero, then inflate is in
+   the middle of a stored block, with the lower value equaling the number of
+   bytes from the input remaining to copy.  If the upper value is not -1, then
+   it is the number of bits back from the current bit position in the input of
+   the code (literal or length/distance pair) currently being processed.  In
+   that case the lower value is the number of bytes already emitted for that
+   code.
+
+     A code is being processed if inflate is waiting for more input to complete
+   decoding of the code, or if it has completed decoding but is waiting for
+   more output space to write the literal or match data.
+
+     inflateMark() is used to mark locations in the input data for random
+   access, which may be at bit positions, and to note those cases where the
+   output of a code may span boundaries of random access blocks.  The current
+   location in the input stream can be determined from avail_in and data_type
+   as noted in the description for the Z_BLOCK flush parameter for inflate.
+
+     inflateMark returns the value noted above or -1 << 16 if the provided
+   source stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
+                                         gz_headerp head));
+/*
+     inflateGetHeader() requests that gzip header information be stored in the
+   provided gz_header structure.  inflateGetHeader() may be called after
+   inflateInit2() or inflateReset(), and before the first call of inflate().
+   As inflate() processes the gzip stream, head->done is zero until the header
+   is completed, at which time head->done is set to one.  If a zlib stream is
+   being decoded, then head->done is set to -1 to indicate that there will be
+   no gzip header information forthcoming.  Note that Z_BLOCK or Z_TREES can be
+   used to force inflate() to return immediately after header processing is
+   complete and before any actual data is decompressed.
+
+     The text, time, xflags, and os fields are filled in with the gzip header
+   contents.  hcrc is set to true if there is a header CRC.  (The header CRC
+   was valid if done is set to one.) If extra is not Z_NULL, then extra_max
+   contains the maximum number of bytes to write to extra.  Once done is true,
+   extra_len contains the actual extra field length, and extra contains the
+   extra field, or that field truncated if extra_max is less than extra_len.
+   If name is not Z_NULL, then up to name_max characters are written there,
+   terminated with a zero unless the length is greater than name_max.  If
+   comment is not Z_NULL, then up to comm_max characters are written there,
+   terminated with a zero unless the length is greater than comm_max.  When any
+   of extra, name, or comment are not Z_NULL and the respective field is not
+   present in the header, then that field is set to Z_NULL to signal its
+   absence.  This allows the use of deflateSetHeader() with the returned
+   structure to duplicate the header.  However if those fields are set to
+   allocated memory, then the application will need to save those pointers
+   elsewhere so that they can be eventually freed.
+
+     If inflateGetHeader is not used, then the header information is simply
+   discarded.  The header is always checked for validity, including the header
+   CRC if present.  inflateReset() will reset the process to discard the header
+   information.  The application would need to call inflateGetHeader() again to
+   retrieve the header from the next gzip stream.
+
+     inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
+                                        unsigned char FAR *window));
+
+     Initialize the internal stream state for decompression using inflateBack()
+   calls.  The fields zalloc, zfree and opaque in strm must be initialized
+   before the call.  If zalloc and zfree are Z_NULL, then the default library-
+   derived memory allocation routines are used.  windowBits is the base two
+   logarithm of the window size, in the range 8..15.  window is a caller
+   supplied buffer of that size.  Except for special applications where it is
+   assured that deflate was used with small window sizes, windowBits must be 15
+   and a 32K byte window must be supplied to be able to decompress general
+   deflate streams.
+
+     See inflateBack() for the usage of these routines.
+
+     inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+   the parameters are invalid, Z_MEM_ERROR if the internal state could not be
+   allocated, or Z_VERSION_ERROR if the version of the library does not match
+   the version of the header file.
+*/
+
+typedef unsigned (*in_func) OF((void FAR *,
+                                z_const unsigned char FAR * FAR *));
+typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
+
+ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
+                                    in_func in, void FAR *in_desc,
+                                    out_func out, void FAR *out_desc));
+/*
+     inflateBack() does a raw inflate with a single call using a call-back
+   interface for input and output.  This is potentially more efficient than
+   inflate() for file i/o applications, in that it avoids copying between the
+   output and the sliding window by simply making the window itself the output
+   buffer.  inflate() can be faster on modern CPUs when used with large
+   buffers.  inflateBack() trusts the application to not change the output
+   buffer passed by the output function, at least until inflateBack() returns.
+
+     inflateBackInit() must be called first to allocate the internal state
+   and to initialize the state with the user-provided window buffer.
+   inflateBack() may then be used multiple times to inflate a complete, raw
+   deflate stream with each call.  inflateBackEnd() is then called to free the
+   allocated state.
+
+     A raw deflate stream is one with no zlib or gzip header or trailer.
+   This routine would normally be used in a utility that reads zip or gzip
+   files and writes out uncompressed files.  The utility would decode the
+   header and process the trailer on its own, hence this routine expects only
+   the raw deflate stream to decompress.  This is different from the normal
+   behavior of inflate(), which expects either a zlib or gzip header and
+   trailer around the deflate stream.
+
+     inflateBack() uses two subroutines supplied by the caller that are then
+   called by inflateBack() for input and output.  inflateBack() calls those
+   routines until it reads a complete deflate stream and writes out all of the
+   uncompressed data, or until it encounters an error.  The function's
+   parameters and return types are defined above in the in_func and out_func
+   typedefs.  inflateBack() will call in(in_desc, &buf) which should return the
+   number of bytes of provided input, and a pointer to that input in buf.  If
+   there is no input available, in() must return zero--buf is ignored in that
+   case--and inflateBack() will return a buffer error.  inflateBack() will call
+   out(out_desc, buf, len) to write the uncompressed data buf[0..len-1].  out()
+   should return zero on success, or non-zero on failure.  If out() returns
+   non-zero, inflateBack() will return with an error.  Neither in() nor out()
+   are permitted to change the contents of the window provided to
+   inflateBackInit(), which is also the buffer that out() uses to write from.
+   The length written by out() will be at most the window size.  Any non-zero
+   amount of input may be provided by in().
+
+     For convenience, inflateBack() can be provided input on the first call by
+   setting strm->next_in and strm->avail_in.  If that input is exhausted, then
+   in() will be called.  Therefore strm->next_in must be initialized before
+   calling inflateBack().  If strm->next_in is Z_NULL, then in() will be called
+   immediately for input.  If strm->next_in is not Z_NULL, then strm->avail_in
+   must also be initialized, and then if strm->avail_in is not zero, input will
+   initially be taken from strm->next_in[0 ..  strm->avail_in - 1].
+
+     The in_desc and out_desc parameters of inflateBack() is passed as the
+   first parameter of in() and out() respectively when they are called.  These
+   descriptors can be optionally used to pass any information that the caller-
+   supplied in() and out() functions need to do their job.
+
+     On return, inflateBack() will set strm->next_in and strm->avail_in to
+   pass back any unused input that was provided by the last in() call.  The
+   return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
+   if in() or out() returned an error, Z_DATA_ERROR if there was a format error
+   in the deflate stream (in which case strm->msg is set to indicate the nature
+   of the error), or Z_STREAM_ERROR if the stream was not properly initialized.
+   In the case of Z_BUF_ERROR, an input or output error can be distinguished
+   using strm->next_in which will be Z_NULL only if in() returned an error.  If
+   strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning
+   non-zero.  (in() will always be called before out(), so strm->next_in is
+   assured to be defined if out() returns non-zero.) Note that inflateBack()
+   cannot return Z_OK.
+*/
+
+ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
+/*
+     All memory allocated by inflateBackInit() is freed.
+
+     inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+   state was inconsistent.
+*/
+
+/* Declaration not used by TNG is not available */
+/*ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));*/
+/* Return flags indicating compile-time options.
+
+    Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+     1.0: size of uInt
+     3.2: size of uLong
+     5.4: size of voidpf (pointer)
+     7.6: size of z_off_t
+
+    Compiler, assembler, and debug options:
+     8: DEBUG
+     9: ASMV or ASMINF -- use ASM code
+     10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+     11: 0 (reserved)
+
+    One-time table building (smaller code, but not thread-safe if true):
+     12: BUILDFIXED -- build static block decoding tables when needed
+     13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+     14,15: 0 (reserved)
+
+    Library content (indicates missing functionality):
+     16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+                          deflate code when not needed)
+     17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+                    and decode gzip streams (to avoid linking crc code)
+     18-19: 0 (reserved)
+
+    Operation variations (changes in library functionality):
+     20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+     21: FASTEST -- deflate algorithm with only one, lowest compression level
+     22,23: 0 (reserved)
+
+    The sprintf variant used by gzprintf (zero is best):
+     24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+     25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+     26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+    Remainder:
+     27-31: 0 (reserved)
+ */
+
+#ifndef Z_SOLO
+
+                        /* utility functions */
+
+/*
+     The following utility functions are implemented on top of the basic
+   stream-oriented functions.  To simplify the interface, some default options
+   are assumed (compression level and memory usage, standard memory allocation
+   functions).  The source code of these utility functions can be modified if
+   you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest,   uLongf *destLen,
+                                 const Bytef *source, uLong sourceLen));
+/*
+     Compresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer.  Upon entry, destLen is the total size
+   of the destination buffer, which must be at least the value returned by
+   compressBound(sourceLen).  Upon exit, destLen is the actual size of the
+   compressed buffer.
+
+     compress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest,   uLongf *destLen,
+                                  const Bytef *source, uLong sourceLen,
+                                  int level));
+/*
+     Compresses the source buffer into the destination buffer.  The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer.  Upon entry, destLen is the total size of the
+   destination buffer, which must be at least the value returned by
+   compressBound(sourceLen).  Upon exit, destLen is the actual size of the
+   compressed buffer.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
+/*
+     compressBound() returns an upper bound on the compressed size after
+   compress() or compress2() on sourceLen bytes.  It would be used before a
+   compress() or compress2() call to allocate the destination buffer.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
+                                   const Bytef *source, uLong sourceLen));
+/*
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer.  Upon entry, destLen is the total size
+   of the destination buffer, which must be large enough to hold the entire
+   uncompressed data.  (The size of the uncompressed data must have been saved
+   previously by the compressor and transmitted to the decompressor by some
+   mechanism outside the scope of this compression library.) Upon exit, destLen
+   is the actual size of the uncompressed buffer.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.  In
+   the case where there is not enough room, uncompress() will fill the output
+   buffer with the uncompressed data up to that point.
+*/
+
+                        /* gzip file access functions */
+
+/*
+     This library supports reading and writing files in gzip (.gz) format with
+   an interface similar to that of stdio, using the functions that start with
+   "gz".  The gzip format is different from the zlib format.  gzip is a gzip
+   wrapper, documented in RFC 1952, wrapped around a deflate stream.
+*/
+
+typedef struct gzFile_s *gzFile;    /* semi-opaque gzip file descriptor */
+
+/*
+ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
+
+     Opens a gzip (.gz) file for reading or writing.  The mode parameter is as
+   in fopen ("rb" or "wb") but can also include a compression level ("wb9") or
+   a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only
+   compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F'
+   for fixed code compression as in "wb9F".  (See the description of
+   deflateInit2 for more information about the strategy parameter.)  'T' will
+   request transparent writing or appending with no compression and not using
+   the gzip format.
+
+     "a" can be used instead of "w" to request that the gzip stream that will
+   be written be appended to the file.  "+" will result in an error, since
+   reading and writing to the same gzip file is not supported.  The addition of
+   "x" when writing will create the file exclusively, which fails if the file
+   already exists.  On systems that support it, the addition of "e" when
+   reading or writing will set the flag to close the file on an execve() call.
+
+     These functions, as well as gzip, will read and decode a sequence of gzip
+   streams in a file.  The append function of gzopen() can be used to create
+   such a file.  (Also see gzflush() for another way to do this.)  When
+   appending, gzopen does not test whether the file begins with a gzip stream,
+   nor does it look for the end of the gzip streams to begin appending.  gzopen
+   will simply append a gzip stream to the existing file.
+
+     gzopen can be used to read a file which is not in gzip format; in this
+   case gzread will directly read from the file without decompression.  When
+   reading, this will be detected automatically by looking for the magic two-
+   byte gzip header.
+
+     gzopen returns NULL if the file could not be opened, if there was
+   insufficient memory to allocate the gzFile state, or if an invalid mode was
+   specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).
+   errno can be checked to determine if the reason gzopen failed was that the
+   file could not be opened.
+*/
+
+ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
+/*
+     gzdopen associates a gzFile with the file descriptor fd.  File descriptors
+   are obtained from calls like open, dup, creat, pipe or fileno (if the file
+   has been previously opened with fopen).  The mode parameter is as in gzopen.
+
+     The next call of gzclose on the returned gzFile will also close the file
+   descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor
+   fd.  If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd,
+   mode);.  The duplicated descriptor should be saved to avoid a leak, since
+   gzdopen does not close fd if it fails.  If you are using fileno() to get the
+   file descriptor from a FILE *, then you will have to use dup() to avoid
+   double-close()ing the file descriptor.  Both gzclose() and fclose() will
+   close the associated file descriptor, so they need to have different file
+   descriptors.
+
+     gzdopen returns NULL if there was insufficient memory to allocate the
+   gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not
+   provided, or '+' was provided), or if fd is -1.  The file descriptor is not
+   used until the next gz* read, write, seek, or close operation, so gzdopen
+   will not detect if fd is invalid (unless fd is -1).
+*/
+
+ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size));
+/*
+     Set the internal buffer size used by this library's functions.  The
+   default buffer size is 8192 bytes.  This function must be called after
+   gzopen() or gzdopen(), and before any other calls that read or write the
+   file.  The buffer memory allocation is always deferred to the first read or
+   write.  Two buffers are allocated, either both of the specified size when
+   writing, or one of the specified size and the other twice that size when
+   reading.  A larger buffer size of, for example, 64K or 128K bytes will
+   noticeably increase the speed of decompression (reading).
+
+     The new buffer size also affects the maximum length for gzprintf().
+
+     gzbuffer() returns 0 on success, or -1 on failure, such as being called
+   too late.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+     Dynamically update the compression level or strategy.  See the description
+   of deflateInit2 for the meaning of these parameters.
+
+     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+   opened for writing.
+*/
+
+ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
+/*
+     Reads the given number of uncompressed bytes from the compressed file.  If
+   the input file is not in gzip format, gzread copies the given number of
+   bytes into the buffer directly from the file.
+
+     After reaching the end of a gzip stream in the input, gzread will continue
+   to read, looking for another gzip stream.  Any number of gzip streams may be
+   concatenated in the input file, and will all be decompressed by gzread().
+   If something other than a gzip stream is encountered after a gzip stream,
+   that remaining trailing garbage is ignored (and no error is returned).
+
+     gzread can be used to read a gzip file that is being concurrently written.
+   Upon reaching the end of the input, gzread will return with the available
+   data.  If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then
+   gzclearerr can be used to clear the end of file indicator in order to permit
+   gzread to be tried again.  Z_OK indicates that a gzip stream was completed
+   on the last gzread.  Z_BUF_ERROR indicates that the input file ended in the
+   middle of a gzip stream.  Note that gzread does not return -1 in the event
+   of an incomplete gzip stream.  This error is deferred until gzclose(), which
+   will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip
+   stream.  Alternatively, gzerror can be used before gzclose to detect this
+   case.
+
+     gzread returns the number of uncompressed bytes actually read, less than
+   len for end of file, or -1 for error.
+*/
+
+ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
+                                voidpc buf, unsigned len));
+/*
+     Writes the given number of uncompressed bytes into the compressed file.
+   gzwrite returns the number of uncompressed bytes written or 0 in case of
+   error.
+*/
+
+ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...));
+/*
+     Converts, formats, and writes the arguments to the compressed file under
+   control of the format string, as in fprintf.  gzprintf returns the number of
+   uncompressed bytes actually written, or 0 in case of error.  The number of
+   uncompressed bytes written is limited to 8191, or one less than the buffer
+   size given to gzbuffer().  The caller should assure that this limit is not
+   exceeded.  If it is exceeded, then gzprintf() will return an error (0) with
+   nothing written.  In this case, there may also be a buffer overflow with
+   unpredictable consequences, which is possible only if zlib was compiled with
+   the insecure functions sprintf() or vsprintf() because the secure snprintf()
+   or vsnprintf() functions were not available.  This can be determined using
+   zlibCompileFlags().
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+     Writes the given null-terminated string to the compressed file, excluding
+   the terminating null character.
+
+     gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+     Reads bytes from the compressed file until len-1 characters are read, or a
+   newline character is read and transferred to buf, or an end-of-file
+   condition is encountered.  If any characters are read or if len == 1, the
+   string is terminated with a null character.  If no characters are read due
+   to an end-of-file or len < 1, then the buffer is left untouched.
+
+     gzgets returns buf which is a null-terminated string, or it returns NULL
+   for end-of-file or in case of error.  If there was an error, the contents at
+   buf are indeterminate.
+*/
+
+ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
+/*
+     Writes c, converted to an unsigned char, into the compressed file.  gzputc
+   returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
+/*
+     Reads one byte from the compressed file.  gzgetc returns this byte or -1
+   in case of end of file or error.  This is implemented as a macro for speed.
+   As such, it does not do all of the checking the other functions do.  I.e.
+   it does not check to see if file is NULL, nor whether the structure file
+   points to has been clobbered or not.
+*/
+
+ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));
+/*
+     Push one character back onto the stream to be read as the first character
+   on the next read.  At least one character of push-back is allowed.
+   gzungetc() returns the character pushed, or -1 on failure.  gzungetc() will
+   fail if c is -1, and may fail if a character has been pushed but not read
+   yet.  If gzungetc is used immediately after gzopen or gzdopen, at least the
+   output buffer size of pushed characters is allowed.  (See gzbuffer above.)
+   The pushed character will be discarded if the stream is repositioned with
+   gzseek() or gzrewind().
+*/
+
+ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
+/*
+     Flushes all pending output into the compressed file.  The parameter flush
+   is as in the deflate() function.  The return value is the zlib error number
+   (see function gzerror below).  gzflush is only permitted when writing.
+
+     If the flush parameter is Z_FINISH, the remaining data is written and the
+   gzip stream is completed in the output.  If gzwrite() is called again, a new
+   gzip stream will be started in the output.  gzread() is able to read such
+   concatented gzip streams.
+
+     gzflush should be called only when strictly necessary because it will
+   degrade compression if called too often.
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
+                                   z_off_t offset, int whence));
+
+     Sets the starting position for the next gzread or gzwrite on the given
+   compressed file.  The offset represents a number of bytes in the
+   uncompressed data stream.  The whence parameter is defined as in lseek(2);
+   the value SEEK_END is not supported.
+
+     If the file is opened for reading, this function is emulated but can be
+   extremely slow.  If the file is opened for writing, only forward seeks are
+   supported; gzseek then compresses a sequence of zeroes up to the new
+   starting position.
+
+     gzseek returns the resulting offset location as measured in bytes from
+   the beginning of the uncompressed stream, or -1 in case of error, in
+   particular if the file is opened for writing and the new starting position
+   would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT    gzrewind OF((gzFile file));
+/*
+     Rewinds the given file. This function is supported only for reading.
+
+     gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT    gztell OF((gzFile file));
+
+     Returns the starting position for the next gzread or gzwrite on the given
+   compressed file.  This position represents a number of bytes in the
+   uncompressed data stream, and is zero when starting, even if appending or
+   reading a gzip stream from the middle of a file using gzdopen().
+
+     gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file));
+
+     Returns the current offset in the file being read or written.  This offset
+   includes the count of bytes that precede the gzip stream, for example when
+   appending or when using gzdopen() for reading.  When reading, the offset
+   does not include as yet unused buffered input.  This information can be used
+   for a progress indicator.  On error, gzoffset() returns -1.
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+     Returns true (1) if the end-of-file indicator has been set while reading,
+   false (0) otherwise.  Note that the end-of-file indicator is set only if the
+   read tried to go past the end of the input, but came up short.  Therefore,
+   just like feof(), gzeof() may return false even if there is no more data to
+   read, in the event that the last read request was for the exact number of
+   bytes remaining in the input file.  This will happen if the input file size
+   is an exact multiple of the buffer size.
+
+     If gzeof() returns true, then the read functions will return no more data,
+   unless the end-of-file indicator is reset by gzclearerr() and the input file
+   has grown since the previous end of file was detected.
+*/
+
+ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
+/*
+     Returns true (1) if file is being copied directly while reading, or false
+   (0) if file is a gzip stream being decompressed.
+
+     If the input file is empty, gzdirect() will return true, since the input
+   does not contain a gzip stream.
+
+     If gzdirect() is used immediately after gzopen() or gzdopen() it will
+   cause buffers to be allocated to allow reading the file to determine if it
+   is a gzip file.  Therefore if gzbuffer() is used, it should be called before
+   gzdirect().
+
+     When writing, gzdirect() returns true (1) if transparent writing was
+   requested ("wT" for the gzopen() mode), or false (0) otherwise.  (Note:
+   gzdirect() is not needed when writing.  Transparent writing must be
+   explicitly requested, so the application already knows the answer.  When
+   linking statically, using gzdirect() will include all of the zlib code for
+   gzip file reading and decompression, which may not be desired.)
+*/
+
+ZEXTERN int ZEXPORT    gzclose OF((gzFile file));
+/*
+     Flushes all pending output if necessary, closes the compressed file and
+   deallocates the (de)compression state.  Note that once file is closed, you
+   cannot call gzerror with file, since its structures have been deallocated.
+   gzclose must not be called more than once on the same file, just as free
+   must not be called more than once on the same allocation.
+
+     gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a
+   file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the
+   last read ended in the middle of a gzip stream, or Z_OK on success.
+*/
+
+ZEXTERN int ZEXPORT gzclose_r OF((gzFile file));
+ZEXTERN int ZEXPORT gzclose_w OF((gzFile file));
+/*
+     Same as gzclose(), but gzclose_r() is only for use when reading, and
+   gzclose_w() is only for use when writing or appending.  The advantage to
+   using these instead of gzclose() is that they avoid linking in zlib
+   compression or decompression code that is not used when only reading or only
+   writing respectively.  If gzclose() is used, then both compression and
+   decompression code will be included the application when linking to a static
+   zlib library.
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+     Returns the error message for the last error which occurred on the given
+   compressed file.  errnum is set to zlib error number.  If an error occurred
+   in the file system and not in the compression library, errnum is set to
+   Z_ERRNO and the application may consult errno to get the exact error code.
+
+     The application must not modify the returned string.  Future calls to
+   this function may invalidate the previously returned string.  If file is
+   closed, then the string previously returned by gzerror will no longer be
+   available.
+
+     gzerror() should be used to distinguish errors from end-of-file for those
+   functions above that do not distinguish those cases in their return values.
+*/
+
+ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
+/*
+     Clears the error and end-of-file flags for file.  This is analogous to the
+   clearerr() function in stdio.  This is useful for continuing to read a gzip
+   file that is being written concurrently.
+*/
+
+#endif /* !Z_SOLO */
+
+                        /* checksum functions */
+
+/*
+     These functions are not related to compression but are exported
+   anyway because they might be useful in applications using the compression
+   library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum.  If buf is Z_NULL, this function returns the
+   required initial value for the checksum.
+
+     An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+   much faster.
+
+   Usage example:
+
+     uLong adler = adler32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       adler = adler32(adler, buffer, length);
+     }
+     if (adler != original_adler) error();
+*/
+
+/*
+ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
+                                          z_off_t len2));
+
+     Combine two Adler-32 checksums into one.  For two sequences of bytes, seq1
+   and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
+   each, adler1 and adler2.  adler32_combine() returns the Adler-32 checksum of
+   seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.  Note
+   that the z_off_t type (like off_t) is a signed integer.  If len2 is
+   negative, the result has no meaning or utility.
+*/
+
+ZEXTERN uLong ZEXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));
+/*
+     Update a running CRC-32 with the bytes buf[0..len-1] and return the
+   updated CRC-32.  If buf is Z_NULL, this function returns the required
+   initial value for the crc.  Pre- and post-conditioning (one's complement) is
+   performed within this function so it shouldn't be done by the application.
+
+   Usage example:
+
+     uLong crc = crc32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       crc = crc32(crc, buffer, length);
+     }
+     if (crc != original_crc) error();
+*/
+
+/*
+ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
+
+     Combine two CRC-32 check values into one.  For two sequences of bytes,
+   seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
+   calculated for each, crc1 and crc2.  crc32_combine() returns the CRC-32
+   check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
+   len2.
+*/
+
+
+                        /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
+                                      int windowBits, int memLevel,
+                                      int strategy, const char *version,
+                                      int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
+                                      const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
+                                         unsigned char FAR *window,
+                                         const char *version,
+                                         int stream_size));
+#define deflateInit(strm, level) \
+        deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))
+#define inflateInit(strm) \
+        inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+                      (strategy), ZLIB_VERSION, (int)sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+        inflateInit2_((strm), (windowBits), ZLIB_VERSION, \
+                      (int)sizeof(z_stream))
+#define inflateBackInit(strm, windowBits, window) \
+        inflateBackInit_((strm), (windowBits), (window), \
+                      ZLIB_VERSION, (int)sizeof(z_stream))
+
+#ifndef Z_SOLO
+
+/* gzgetc() macro and its supporting function and exposed data structure.  Note
+ * that the real internal state is much larger than the exposed structure.
+ * This abbreviated structure exposes just enough for the gzgetc() macro.  The
+ * user should not mess with these exposed elements, since their names or
+ * behavior could change in the future, perhaps even capriciously.  They can
+ * only be used by the gzgetc() macro.  You have been warned.
+ */
+struct gzFile_s {
+    unsigned have;
+    unsigned char *next;
+    z_off64_t pos;
+};
+ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file));  /* backward compatibility */
+#ifdef Z_PREFIX_SET
+#  undef z_gzgetc
+#  define z_gzgetc(g) \
+          ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))
+#else
+#  define gzgetc(g) \
+          ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))
+#endif
+
+/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or
+ * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if
+ * both are true, the application gets the *64 functions, and the regular
+ * functions are changed to 64 bits) -- in case these are set on systems
+ * without large file support, _LFS64_LARGEFILE must also be true
+ */
+#ifdef Z_LARGE64
+   ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+   ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));
+   ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));
+   ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));
+   ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t));
+   ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t));
+#endif
+
+#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64)
+#  ifdef Z_PREFIX_SET
+#    define z_gzopen z_gzopen64
+#    define z_gzseek z_gzseek64
+#    define z_gztell z_gztell64
+#    define z_gzoffset z_gzoffset64
+#    define z_adler32_combine z_adler32_combine64
+#    define z_crc32_combine z_crc32_combine64
+#  else
+#    define gzopen gzopen64
+#    define gzseek gzseek64
+#    define gztell gztell64
+#    define gzoffset gzoffset64
+#    define adler32_combine adler32_combine64
+#    define crc32_combine crc32_combine64
+#  endif
+#  ifndef Z_LARGE64
+     ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+     ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int));
+     ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile));
+     ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile));
+     ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
+     ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
+#  endif
+#else
+   ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *));
+   ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int));
+   ZEXTERN z_off_t ZEXPORT gztell OF((gzFile));
+   ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile));
+   ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));
+   ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));
+#endif
+
+#else /* Z_SOLO */
+
+   ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));
+   ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));
+
+#endif /* !Z_SOLO */
+
+/* hack for buggy compilers */
+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
+    struct internal_state {int dummy;};
+#endif
+
+/* undocumented functions */
+ZEXTERN const char   * ZEXPORT zError           OF((int));
+ZEXTERN int            ZEXPORT inflateSyncPoint OF((z_streamp));
+ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table    OF((void));
+ZEXTERN int            ZEXPORT inflateUndermine OF((z_streamp, int));
+ZEXTERN int            ZEXPORT inflateResetKeep OF((z_streamp));
+ZEXTERN int            ZEXPORT deflateResetKeep OF((z_streamp));
+#if defined(_WIN32) && !defined(Z_SOLO)
+ZEXTERN gzFile         ZEXPORT gzopen_w OF((const wchar_t *path,
+                                            const char *mode));
+#endif
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#  ifndef Z_SOLO
+ZEXTERN int            ZEXPORTVA gzvprintf Z_ARG((gzFile file,
+                                                  const char *format,
+                                                  va_list va));
+#  endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZLIB_H */
diff --git a/src/external/tng_io/external/zlib/zutil.c b/src/external/tng_io/external/zlib/zutil.c
new file mode 100644 (file)
index 0000000..fbd3587
--- /dev/null
@@ -0,0 +1,323 @@
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-2005, 2010, 2011, 2012 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zutil.h"
+
+#ifndef NO_DUMMY_DECL
+struct internal_state      {int dummy;}; /* for buggy compilers */
+#endif
+
+z_const char * const z_errmsg[10] = {
+"need dictionary",     /* Z_NEED_DICT       2  */
+"stream end",          /* Z_STREAM_END      1  */
+"",                    /* Z_OK              0  */
+"file error",          /* Z_ERRNO         (-1) */
+"stream error",        /* Z_STREAM_ERROR  (-2) */
+"data error",          /* Z_DATA_ERROR    (-3) */
+"insufficient memory", /* Z_MEM_ERROR     (-4) */
+"buffer error",        /* Z_BUF_ERROR     (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char * ZEXPORT zlibVersion()
+{
+    return ZLIB_VERSION;
+}
+
+/* This function is not used by TNG
+uLong ZEXPORT zlibCompileFlags()
+{
+    uLong flags;
+
+    flags = 0;
+    switch ((int)(sizeof(uInt))) {
+    case 2:     break;
+    case 4:     flags += 1;     break;
+    case 8:     flags += 2;     break;
+    default:    flags += 3;
+    }
+    switch ((int)(sizeof(uLong))) {
+    case 2:     break;
+    case 4:     flags += 1 << 2;        break;
+    case 8:     flags += 2 << 2;        break;
+    default:    flags += 3 << 2;
+    }
+    switch ((int)(sizeof(voidpf))) {
+    case 2:     break;
+    case 4:     flags += 1 << 4;        break;
+    case 8:     flags += 2 << 4;        break;
+    default:    flags += 3 << 4;
+    }
+    switch ((int)(sizeof(z_off_t))) {
+    case 2:     break;
+    case 4:     flags += 1 << 6;        break;
+    case 8:     flags += 2 << 6;        break;
+    default:    flags += 3 << 6;
+    }
+#ifdef DEBUG
+    flags += 1 << 8;
+#endif
+#if defined(ASMV) || defined(ASMINF)
+    flags += 1 << 9;
+#endif
+#ifdef ZLIB_WINAPI
+    flags += 1 << 10;
+#endif
+#ifdef BUILDFIXED
+    flags += 1 << 12;
+#endif
+#ifdef DYNAMIC_CRC_TABLE
+    flags += 1 << 13;
+#endif
+#ifdef NO_GZCOMPRESS
+    flags += 1L << 16;
+#endif
+#ifdef NO_GZIP
+    flags += 1L << 17;
+#endif
+#ifdef PKZIP_BUG_WORKAROUND
+    flags += 1L << 20;
+#endif
+#ifdef FASTEST
+    flags += 1L << 21;
+#endif
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#  ifdef NO_vsnprintf
+    flags += 1L << 25;
+#    ifdef HAS_vsprintf_void
+    flags += 1L << 26;
+#    endif
+#  else
+#    ifdef HAS_vsnprintf_void
+    flags += 1L << 26;
+#    endif
+#  endif
+#else
+    flags += 1L << 24;
+#  ifdef NO_snprintf
+    flags += 1L << 25;
+#    ifdef HAS_sprintf_void
+    flags += 1L << 26;
+#    endif
+#  else
+#    ifdef HAS_snprintf_void
+    flags += 1L << 26;
+#    endif
+#  endif
+#endif
+    return flags;
+}
+*/
+
+#ifdef DEBUG
+
+#  ifndef verbose
+#    define verbose 0
+#  endif
+int ZLIB_INTERNAL z_verbose = verbose;
+
+void ZLIB_INTERNAL z_error (m)
+    char *m;
+{
+    fprintf(stderr, "%s\n", m);
+    exit(1);
+}
+#endif
+
+/* exported to allow conversion of error code to string for compress() and
+ * uncompress()
+ */
+const char * ZEXPORT zError(err)
+    int err;
+{
+    return ERR_MSG(err);
+}
+
+#if defined(_WIN32_WCE)
+    /* The Microsoft C Run-Time Library for Windows CE doesn't have
+     * errno.  We define it as a global variable to simplify porting.
+     * Its value is always 0 and should not be used.
+     */
+    int errno = 0;
+#endif
+
+#ifndef HAVE_MEMCPY
+
+void ZLIB_INTERNAL zmemcpy(dest, source, len)
+    Bytef* dest;
+    const Bytef* source;
+    uInt  len;
+{
+    if (len == 0) return;
+    do {
+        *dest++ = *source++; /* ??? to be unrolled */
+    } while (--len != 0);
+}
+
+int ZLIB_INTERNAL zmemcmp(s1, s2, len)
+    const Bytef* s1;
+    const Bytef* s2;
+    uInt  len;
+{
+    uInt j;
+
+    for (j = 0; j < len; j++) {
+        if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+    }
+    return 0;
+}
+
+void ZLIB_INTERNAL zmemzero(dest, len)
+    Bytef* dest;
+    uInt  len;
+{
+    if (len == 0) return;
+    do {
+        *dest++ = 0;  /* ??? to be unrolled */
+    } while (--len != 0);
+}
+#endif
+
+#ifndef Z_SOLO
+
+#ifdef SYS16BIT
+
+#ifdef __TURBOC__
+/* Turbo C in 16-bit mode */
+
+#  define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+    voidpf org_ptr;
+    voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+    voidpf buf = opaque; /* just to make some compilers happy */
+    ulg bsize = (ulg)items*size;
+
+    /* If we allocate less than 65520 bytes, we assume that farmalloc
+     * will return a usable pointer which doesn't have to be normalized.
+     */
+    if (bsize < 65520L) {
+        buf = farmalloc(bsize);
+        if (*(ush*)&buf != 0) return buf;
+    } else {
+        buf = farmalloc(bsize + 16L);
+    }
+    if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+    table[next_ptr].org_ptr = buf;
+
+    /* Normalize the pointer to seg:0 */
+    *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+    *(ush*)&buf = 0;
+    table[next_ptr++].new_ptr = buf;
+    return buf;
+}
+
+void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
+{
+    int n;
+    if (*(ush*)&ptr != 0) { /* object < 64K */
+        farfree(ptr);
+        return;
+    }
+    /* Find the original pointer */
+    for (n = 0; n < next_ptr; n++) {
+        if (ptr != table[n].new_ptr) continue;
+
+        farfree(table[n].org_ptr);
+        while (++n < next_ptr) {
+            table[n-1] = table[n];
+        }
+        next_ptr--;
+        return;
+    }
+    ptr = opaque; /* just to make some compilers happy */
+    Assert(0, "zcfree: ptr not found");
+}
+
+#endif /* __TURBOC__ */
+
+
+#ifdef M_I86
+/* Microsoft C in 16-bit mode */
+
+#  define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+#  define _halloc  halloc
+#  define _hfree   hfree
+#endif
+
+voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size)
+{
+    if (opaque) opaque = 0; /* to make compiler happy */
+    return _halloc((long)items, size);
+}
+
+void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
+{
+    if (opaque) opaque = 0; /* to make compiler happy */
+    _hfree(ptr);
+}
+
+#endif /* M_I86 */
+
+#endif /* SYS16BIT */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp  malloc OF((uInt size));
+extern voidp  calloc OF((uInt items, uInt size));
+extern void   free   OF((voidpf ptr));
+#endif
+
+voidpf ZLIB_INTERNAL zcalloc (opaque, items, size)
+    voidpf opaque;
+    unsigned items;
+    unsigned size;
+{
+    if (opaque) items += size - size; /* make compiler happy */
+    return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
+                              (voidpf)calloc(items, size);
+}
+
+void ZLIB_INTERNAL zcfree (opaque, ptr)
+    voidpf opaque;
+    voidpf ptr;
+{
+    free(ptr);
+    if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
+
+#endif /* !Z_SOLO */
diff --git a/src/external/tng_io/external/zlib/zutil.h b/src/external/tng_io/external/zlib/zutil.h
new file mode 100644 (file)
index 0000000..24ab06b
--- /dev/null
@@ -0,0 +1,253 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-2013 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZUTIL_H
+#define ZUTIL_H
+
+#ifdef HAVE_HIDDEN
+#  define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
+#else
+#  define ZLIB_INTERNAL
+#endif
+
+#include "zlib.h"
+
+#if defined(STDC) && !defined(Z_SOLO)
+#  if !(defined(_WIN32_WCE) && defined(_MSC_VER))
+#    include <stddef.h>
+#  endif
+#  include <string.h>
+#  include <stdlib.h>
+#endif
+
+#ifdef Z_SOLO
+   typedef long ptrdiff_t;  /* guess -- will be caught if guess is wrong */
+#endif
+
+#ifndef local
+#  define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char  uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long  ulg;
+
+extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+  return (strm->msg = ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+        /* common constants */
+
+#ifndef DEF_WBITS
+#  define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+#  define DEF_MEM_LEVEL 8
+#else
+#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES    2
+/* The three kinds of block type */
+
+#define MIN_MATCH  3
+#define MAX_MATCH  258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+        /* target dependencies */
+
+#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
+#  define OS_CODE  0x00
+#  ifndef Z_SOLO
+#    if defined(__TURBOC__) || defined(__BORLANDC__)
+#      if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
+         /* Allow compilation with ANSI keywords only enabled */
+         void _Cdecl farfree( void *block );
+         void *_Cdecl farmalloc( unsigned long nbytes );
+#      else
+#        include <alloc.h>
+#      endif
+#    else /* MSC or DJGPP */
+#      include <malloc.h>
+#    endif
+#  endif
+#endif
+
+#ifdef AMIGA
+#  define OS_CODE  0x01
+#endif
+
+#if defined(VAXC) || defined(VMS)
+#  define OS_CODE  0x02
+#  define F_OPEN(name, mode) \
+     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#if defined(ATARI) || defined(atarist)
+#  define OS_CODE  0x05
+#endif
+
+#ifdef OS2
+#  define OS_CODE  0x06
+#  if defined(M_I86) && !defined(Z_SOLO)
+#    include <malloc.h>
+#  endif
+#endif
+
+#if defined(MACOS) || defined(TARGET_OS_MAC)
+#  define OS_CODE  0x07
+#  ifndef Z_SOLO
+#    if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+#      include <unix.h> /* for fdopen */
+#    else
+#      ifndef fdopen
+#        define fdopen(fd,mode) NULL /* No fdopen() */
+#      endif
+#    endif
+#  endif
+#endif
+
+#ifdef TOPS20
+#  define OS_CODE  0x0a
+#endif
+
+#ifdef WIN32
+#  ifndef __CYGWIN__  /* Cygwin is Unix, not Win32 */
+#    define OS_CODE  0x0b
+#  endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+#  define OS_CODE  0x0f
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+#  define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX
+#  if defined(_WIN32_WCE)
+#    define fdopen(fd,mode) NULL /* No fdopen() */
+#    ifndef _PTRDIFF_T_DEFINED
+       typedef int ptrdiff_t;
+#      define _PTRDIFF_T_DEFINED
+#    endif
+#  else
+#    define fdopen(fd,type)  _fdopen(fd,type)
+#  endif
+#endif
+
+#if defined(__BORLANDC__) && !defined(MSDOS)
+  #pragma warn -8004
+  #pragma warn -8008
+  #pragma warn -8066
+#endif
+
+/* provide prototypes for these when building zlib without LFS */
+#if !defined(_WIN32) && \
+    (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)
+    ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
+    ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
+#endif
+
+        /* common defaults */
+
+#ifndef OS_CODE
+#  define OS_CODE  0x03  /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+#  define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+         /* functions */
+
+#if defined(pyr) || defined(Z_SOLO)
+#  define NO_MEMCPY
+#endif
+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+  * You may have to use the same strategy for Borland C (untested).
+  * The __SC__ check is for Symantec.
+  */
+#  define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+#  define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+#    define zmemcpy _fmemcpy
+#    define zmemcmp _fmemcmp
+#    define zmemzero(dest, len) _fmemset(dest, 0, len)
+#  else
+#    define zmemcpy memcpy
+#    define zmemcmp memcmp
+#    define zmemzero(dest, len) memset(dest, 0, len)
+#  endif
+#else
+   void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));
+   int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));
+   void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG
+#  include <stdio.h>
+   extern int ZLIB_INTERNAL z_verbose;
+   extern void ZLIB_INTERNAL z_error OF((char *m));
+#  define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+#  define Trace(x) {if (z_verbose>=0) fprintf x ;}
+#  define Tracev(x) {if (z_verbose>0) fprintf x ;}
+#  define Tracevv(x) {if (z_verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+#ifndef Z_SOLO
+   voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items,
+                                    unsigned size));
+   void ZLIB_INTERNAL zcfree  OF((voidpf opaque, voidpf ptr));
+#endif
+
+#define ZALLOC(strm, items, size) \
+           (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+/* Reverse the bytes in a 32-bit value */
+#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
+                    (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
+
+#endif /* ZUTIL_H */
index d8ff0fea228500478f0a132b1e7256bf5ed49666..750d38e8be7095448a3e2f657ad37648ff2aa568 100644 (file)
@@ -459,36 +459,73 @@ typedef enum {TNG_NON_TRAJECTORY_BLOCK, TNG_TRAJECTORY_BLOCK} tng_block_type;
 #define TNG_GMX_ENERGY_TEMPERATURE      0x1000000010000011LL
 #define TNG_GMX_ENERGY_PRESSURE         0x1000000010000012LL
 #define TNG_GMX_ENERGY_CONSTR_RMSD      0x1000000010000013LL
-#define TNG_GMX_ENERGY_BOX_X            0x1000000010000014LL
-#define TNG_GMX_ENERGY_BOX_Y            0x1000000010000015LL
-#define TNG_GMX_ENERGY_BOX_Z            0x1000000010000016LL
-#define TNG_GMX_ENERGY_VOLUME           0x1000000010000017LL
-#define TNG_GMX_ENERGY_DENSITY          0x1000000010000018LL
-#define TNG_GMX_ENERGY_PV               0x1000000010000019LL
-#define TNG_GMX_ENERGY_ENTHALPY         0x1000000010000020LL
-#define TNG_GMX_ENERGY_VIR_XX           0x1000000010000021LL
-#define TNG_GMX_ENERGY_VIR_XY           0x1000000010000022LL
-#define TNG_GMX_ENERGY_VIR_XZ           0x1000000010000023LL
-#define TNG_GMX_ENERGY_VIR_YX           0x1000000010000024LL
-#define TNG_GMX_ENERGY_VIR_YY           0x1000000010000025LL
-#define TNG_GMX_ENERGY_VIR_YZ           0x1000000010000026LL
-#define TNG_GMX_ENERGY_VIR_ZX           0x1000000010000027LL
-#define TNG_GMX_ENERGY_VIR_ZY           0x1000000010000028LL
-#define TNG_GMX_ENERGY_VIR_ZZ           0x1000000010000029LL
-#define TNG_GMX_ENERGY_PRES_XX          0x1000000010000030LL
-#define TNG_GMX_ENERGY_PRES_XY          0x1000000010000031LL
-#define TNG_GMX_ENERGY_PRES_XZ          0x1000000010000032LL
-#define TNG_GMX_ENERGY_PRES_YX          0x1000000010000033LL
-#define TNG_GMX_ENERGY_PRES_YY          0x1000000010000034LL
-#define TNG_GMX_ENERGY_PRES_YZ          0x1000000010000035LL
-#define TNG_GMX_ENERGY_PRES_ZX          0x1000000010000036LL
-#define TNG_GMX_ENERGY_PRES_ZY          0x1000000010000037LL
-#define TNG_GMX_ENERGY_PRES_ZZ          0x1000000010000038LL
-#define TNG_GMX_ENERGY_SURFXSURFTEN     0x1000000010000039LL
-#define TNG_GMX_ENERGY_T_SYSTEM         0x1000000010000040LL
-#define TNG_GMX_ENERGY_LAMB_SYSTEM      0x1000000010000041LL
-#define TNG_GMX_SELECTION_GROUP_NAMES   0x1000000010000042LL
-#define TNG_GMX_ATOM_SELECTION_GROUP    0x1000000010000043LL
+#define TNG_GMX_ENERGY_CONSTR2_RMSD     0x1000000010000014LL
+#define TNG_GMX_ENERGY_BOX_X            0x1000000010000015LL
+#define TNG_GMX_ENERGY_BOX_Y            0x1000000010000016LL
+#define TNG_GMX_ENERGY_BOX_Z            0x1000000010000017LL
+#define TNG_GMX_ENERGY_BOXXX            0x1000000010000018LL
+#define TNG_GMX_ENERGY_BOXYY            0x1000000010000019LL
+#define TNG_GMX_ENERGY_BOXZZ            0x1000000010000020LL
+#define TNG_GMX_ENERGY_BOXYX            0x1000000010000021LL
+#define TNG_GMX_ENERGY_BOXZX            0x1000000010000022LL
+#define TNG_GMX_ENERGY_BOXZY            0x1000000010000023LL
+#define TNG_GMX_ENERGY_BOXVELXX         0x1000000010000024LL
+#define TNG_GMX_ENERGY_BOXVELYY         0x1000000010000025LL
+#define TNG_GMX_ENERGY_BOXVELZZ         0x1000000010000026LL
+#define TNG_GMX_ENERGY_BOXVELYX         0x1000000010000027LL
+#define TNG_GMX_ENERGY_BOXVELZX         0x1000000010000028LL
+#define TNG_GMX_ENERGY_BOXVELZY         0x1000000010000029LL
+#define TNG_GMX_ENERGY_VOLUME           0x1000000010000030LL
+#define TNG_GMX_ENERGY_DENSITY          0x1000000010000031LL
+#define TNG_GMX_ENERGY_PV               0x1000000010000032LL
+#define TNG_GMX_ENERGY_ENTHALPY         0x1000000010000033LL
+#define TNG_GMX_ENERGY_VIR_XX           0x1000000010000034LL
+#define TNG_GMX_ENERGY_VIR_XY           0x1000000010000035LL
+#define TNG_GMX_ENERGY_VIR_XZ           0x1000000010000036LL
+#define TNG_GMX_ENERGY_VIR_YX           0x1000000010000037LL
+#define TNG_GMX_ENERGY_VIR_YY           0x1000000010000038LL
+#define TNG_GMX_ENERGY_VIR_YZ           0x1000000010000039LL
+#define TNG_GMX_ENERGY_VIR_ZX           0x1000000010000040LL
+#define TNG_GMX_ENERGY_VIR_ZY           0x1000000010000041LL
+#define TNG_GMX_ENERGY_VIR_ZZ           0x1000000010000042LL
+#define TNG_GMX_ENERGY_SHAKEVIR_XX      0x1000000010000043LL
+#define TNG_GMX_ENERGY_SHAKEVIR_XY      0x1000000010000044LL
+#define TNG_GMX_ENERGY_SHAKEVIR_XZ      0x1000000010000045LL
+#define TNG_GMX_ENERGY_SHAKEVIR_YX      0x1000000010000046LL
+#define TNG_GMX_ENERGY_SHAKEVIR_YY      0x1000000010000047LL
+#define TNG_GMX_ENERGY_SHAKEVIR_YZ      0x1000000010000048LL
+#define TNG_GMX_ENERGY_SHAKEVIR_ZX      0x1000000010000049LL
+#define TNG_GMX_ENERGY_SHAKEVIR_ZY      0x1000000010000050LL
+#define TNG_GMX_ENERGY_SHAKEVIR_ZZ      0x1000000010000051LL
+#define TNG_GMX_ENERGY_FORCEVIR_XX      0x1000000010000052LL
+#define TNG_GMX_ENERGY_FORCEVIR_XY      0x1000000010000053LL
+#define TNG_GMX_ENERGY_FORCEVIR_XZ      0x1000000010000054LL
+#define TNG_GMX_ENERGY_FORCEVIR_YX      0x1000000010000055LL
+#define TNG_GMX_ENERGY_FORCEVIR_YY      0x1000000010000056LL
+#define TNG_GMX_ENERGY_FORCEVIR_YZ      0x1000000010000057LL
+#define TNG_GMX_ENERGY_FORCEVIR_ZX      0x1000000010000058LL
+#define TNG_GMX_ENERGY_FORCEVIR_ZY      0x1000000010000059LL
+#define TNG_GMX_ENERGY_FORCEVIR_ZZ      0x1000000010000060LL
+#define TNG_GMX_ENERGY_PRES_XX          0x1000000010000061LL
+#define TNG_GMX_ENERGY_PRES_XY          0x1000000010000062LL
+#define TNG_GMX_ENERGY_PRES_XZ          0x1000000010000063LL
+#define TNG_GMX_ENERGY_PRES_YX          0x1000000010000064LL
+#define TNG_GMX_ENERGY_PRES_YY          0x1000000010000065LL
+#define TNG_GMX_ENERGY_PRES_YZ          0x1000000010000066LL
+#define TNG_GMX_ENERGY_PRES_ZX          0x1000000010000067LL
+#define TNG_GMX_ENERGY_PRES_ZY          0x1000000010000068LL
+#define TNG_GMX_ENERGY_PRES_ZZ          0x1000000010000069LL
+#define TNG_GMX_ENERGY_SURFXSURFTEN     0x1000000010000070LL
+#define TNG_GMX_ENERGY_MUX              0x1000000010000071LL
+#define TNG_GMX_ENERGY_MUY              0x1000000010000072LL
+#define TNG_GMX_ENERGY_MUZ              0x1000000010000073LL
+#define TNG_GMX_ENERGY_VCOS             0x1000000010000074LL
+#define TNG_GMX_ENERGY_VISC             0x1000000010000075LL
+#define TNG_GMX_ENERGY_BAROSTAT         0x1000000010000076LL
+#define TNG_GMX_ENERGY_T_SYSTEM         0x1000000010000077LL
+#define TNG_GMX_ENERGY_LAMB_SYSTEM      0x1000000010000078LL
+#define TNG_GMX_SELECTION_GROUP_NAMES   0x1000000010000079LL
+#define TNG_GMX_ATOM_SELECTION_GROUP    0x1000000010000080LL
 /** @} */
 
 /** Flag to specify if a data block contains data related to particles or not.*/
@@ -2976,7 +3013,8 @@ tng_function_status DECLSPECDLLEXPORT tng_data_get(const tng_trajectory_t tng_da
  * opened.
  * @param block_id is the id number of the particle data block to read.
  * @param values is a pointer to a 1-dimensional array (memory unallocated), which
- * will be filled with data. The length of the array will be (n_frames * n_values_per_frame).
+ * will be filled with data. The length of the array will be
+ * (n_frames_with_data (see stride_length) * n_values_per_frame).
  * Since **values is allocated in this function it is the callers
  * responsibility to free the memory.
  * @param n_frames is set to the number of particles in the returned data. This is
@@ -3063,7 +3101,8 @@ tng_function_status DECLSPECDLLEXPORT tng_data_interval_get
  * If hash_mode == TNG_USE_HASH the md5 hash in the file will be
  * compared to the md5 hash of the read contents to ensure valid data.
  * @param values is a pointer to a 1-dimensional array (memory unallocated), which
- * will be filled with data. The length of the array will be (n_frames * n_values_per_frame).
+ * will be filled with data. The length of the array will be
+ * (n_frames_with_data (see stride_length) * n_values_per_frame).
  * Since **values is allocated in this function it is the callers
  * responsibility to free the memory.
  * @param stride_length is set to the stride length (writing interval) of
@@ -3152,7 +3191,7 @@ tng_function_status DECLSPECDLLEXPORT tng_particle_data_get
  * @param block_id is the id number of the particle data block to read.
  * @param values is a pointer to a 1-dimensional array (memory unallocated), which
  * will be filled with data. The length of the array will be
- * (n_frames * n_particles * n_values_per_frame).
+ * (n_frames_with_data (see stride_length) * n_particles * n_values_per_frame).
  * Since **values is allocated in this function it is the callers
  * responsibility to free the memory.
  * @param n_frames is set to the number of frames in the returned data. This is
@@ -3256,7 +3295,7 @@ tng_function_status DECLSPECDLLEXPORT tng_particle_data_interval_get
  * compared to the md5 hash of the read contents to ensure valid data.
  * @param values is a pointer to a 1-dimensional array (memory unallocated), which
  * will be filled with data. The length of the array will be
- * (n_frames * n_particles * n_values_per_frame).
+ * (n_frames_with_data (see stride_length) * n_particles * n_values_per_frame).
  * Since **values is allocated in this function it is the callers
  * responsibility to free the memory.
  * @param stride_length is set to the stride length (writing interval) of
index 06c0470677a980f64aa71b0a8182b75aa68d0dab..537510fbb35829bbd55a3e541001f20c1d462569 100644 (file)
@@ -1,13 +1,15 @@
 # - Config file for the TNG_IO package
-# It defines the following variables
-#  TNG_IO_INCLUDE_DIRS - include directories for TNG_IO
-#  TNG_IO_LIBRARIES    - libraries to link against
-#  TNG_IO_DEFINITIONS - definitions used when compiling
 
-# Compute paths
-get_filename_component(TNG_IO_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
-set(TNG_IO_INCLUDE_DIRS "@CONF_INCLUDE_DIRS@")
-set(TNG_IO_DEFINITIONS "@TNG_COMPILE_DEFS@")
+include(${CMAKE_CURRENT_LIST_DIR}/tng_io.cmake)
 
-set(TNG_IO_LIBRARIES tng_io)
+get_target_property(_libs tng_io::tng_io INTERFACE_LINK_LIBRARIES)
+if (_libs MATCHES "ZLIB::")
+    include(CMakeFindDependencyMacro)
+    find_dependency(ZLIB)
+endif()
+unset(_libs)
 
+# Provide information in variables as well for backwards compatibility
+set(TNG_IO_LIBRARIES tng_io::tng_io)
+get_target_property(TNG_IO_INCLUDE_DIRS tng_io::tng_io INTERFACE_INCLUDE_DIRECTORIES)
+get_target_property(TNG_IO_DEFINITIONS tng_io::tng_io INTERFACE_COMPILE_DEFINITIONS)
index f0ed8d60b7768799f3312c7f8390fb2db1c3deed..19e9164d9b611380a372392674833d67512ebba5 100644 (file)
@@ -28,9 +28,7 @@
 #include <string.h>
 #include <time.h>
 #include <math.h>
-#ifdef USE_ZLIB
 #include <zlib.h>
-#endif
 
 #include "tng/md5.h"
 #include "compression/tng_compress.h"
@@ -258,16 +256,16 @@ struct tng_trajectory {
     FILE *output_file;
     /** Function to swap 32 bit values to and from the endianness of the
      * input file */
-    tng_function_status (*input_endianness_swap_func_32)(const tng_trajectory_t, int32_t *);
+    tng_function_status (*input_endianness_swap_func_32)(const tng_trajectory_t, uint32_t *);
     /** Function to swap 64 bit values to and from the endianness of the
      * input file */
-    tng_function_status (*input_endianness_swap_func_64)(const tng_trajectory_t, int64_t *);
+    tng_function_status (*input_endianness_swap_func_64)(const tng_trajectory_t, uint64_t *);
     /** Function to swap 32 bit values to and from the endianness of the
      * input file */
-    tng_function_status (*output_endianness_swap_func_32)(const tng_trajectory_t, int32_t *);
+    tng_function_status (*output_endianness_swap_func_32)(const tng_trajectory_t, uint32_t *);
     /** Function to swap 64 bit values to and from the endianness of the
      * input file */
-    tng_function_status (*output_endianness_swap_func_64)(const tng_trajectory_t, int64_t *);
+    tng_function_status (*output_endianness_swap_func_64)(const tng_trajectory_t, uint64_t *);
     /** The endianness of 32 bit values of the current computer */
     char endianness_32;
     /** The endianness of 64 bit values of the current computer */
@@ -402,7 +400,7 @@ static TNG_INLINE int64_t tng_max_i64(const int64_t a, const int64_t b)
  * byte order is not recognised.
  */
 static tng_function_status tng_swap_byte_order_big_endian_32
-                (const tng_trajectory_t tng_data, int32_t *v)
+                (const tng_trajectory_t tng_data, uint32_t *v)
 {
     switch(tng_data->endianness_32)
     {
@@ -441,7 +439,7 @@ static tng_function_status tng_swap_byte_order_big_endian_32
  * byte order is not recognised.
  */
 static tng_function_status tng_swap_byte_order_big_endian_64
-                (const tng_trajectory_t tng_data, int64_t *v)
+                (const tng_trajectory_t tng_data, uint64_t *v)
 {
     switch(tng_data->endianness_64)
     {
@@ -494,7 +492,7 @@ static tng_function_status tng_swap_byte_order_big_endian_64
  * byte order is not recognised.
  */
 static tng_function_status tng_swap_byte_order_little_endian_32
-                (const tng_trajectory_t tng_data, int32_t *v)
+                (const tng_trajectory_t tng_data, uint32_t *v)
 {
     switch(tng_data->endianness_32)
     {
@@ -533,7 +531,7 @@ static tng_function_status tng_swap_byte_order_little_endian_32
  * byte order is not recognised.
  */
 static tng_function_status tng_swap_byte_order_little_endian_64
-                (const tng_trajectory_t tng_data, int64_t *v)
+                (const tng_trajectory_t tng_data, uint64_t *v)
 {
     switch(tng_data->endianness_64)
     {
@@ -619,11 +617,10 @@ static tng_function_status tng_freadstr(const tng_trajectory_t tng_data,
         }
     } while ((temp[count-1] != '\0') && (count < TNG_MAX_STR_LEN));
 
-    temp_alloc = realloc(*str, count);
+    temp_alloc = (char *)realloc(*str, count);
     if(!temp_alloc)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", count,
-               __FILE__, line_nr);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, line_nr);
         free(*str);
         *str = 0;
         return TNG_FAILURE;
@@ -708,7 +705,7 @@ static TNG_INLINE tng_function_status tng_file_input_numerical
     {
     case 8:
         if(tng_data->input_endianness_swap_func_64 &&
-           tng_data->input_endianness_swap_func_64(tng_data, dest) != TNG_SUCCESS)
+           tng_data->input_endianness_swap_func_64(tng_data, (uint64_t *)dest) != TNG_SUCCESS)
         {
             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
                     __FILE__, line_nr);
@@ -716,7 +713,7 @@ static TNG_INLINE tng_function_status tng_file_input_numerical
         break;
     case 4:
         if(tng_data->input_endianness_swap_func_32 &&
-           tng_data->input_endianness_swap_func_32(tng_data, dest) != TNG_SUCCESS)
+           tng_data->input_endianness_swap_func_32(tng_data, (uint32_t *)dest) != TNG_SUCCESS)
         {
             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
                     __FILE__, line_nr);
@@ -750,13 +747,13 @@ static TNG_INLINE tng_function_status tng_file_output_numerical
                  md5_state_t *md5_state,
                  const int line_nr)
 {
-    int32_t temp_i32;
-    int64_t temp_i64;
+    uint32_t temp_i32;
+    uint64_t temp_i64;
 
     switch(len)
     {
         case 8:
-            temp_i64 = *((int64_t *)src);
+            temp_i64 = *((uint64_t *)src);
             if(tng_data->output_endianness_swap_func_64 &&
             tng_data->output_endianness_swap_func_64(tng_data, &temp_i64) != TNG_SUCCESS)
             {
@@ -774,7 +771,7 @@ static TNG_INLINE tng_function_status tng_file_output_numerical
             }
             break;
         case 4:
-            temp_i32 = *((int32_t *)src);
+            temp_i32 = *((uint32_t *)src);
             if(tng_data->output_endianness_swap_func_32 &&
             tng_data->output_endianness_swap_func_32(tng_data, &temp_i32) != TNG_SUCCESS)
             {
@@ -846,11 +843,11 @@ static tng_function_status tng_md5_remaining_append(const tng_trajectory_t tng_d
     curr_file_pos = ftello(tng_data->input_file);
     if(curr_file_pos < start_pos + block->block_contents_size)
     {
-        temp_data = malloc(start_pos + block->block_contents_size - curr_file_pos);
+        temp_data = (char *)malloc(start_pos + block->block_contents_size - curr_file_pos);
         if(!temp_data)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
-                    start_pos + block->block_contents_size - curr_file_pos, __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
         if(fread(temp_data, start_pos + block->block_contents_size - curr_file_pos,
@@ -946,11 +943,10 @@ static tng_function_status tng_block_init(struct tng_gen_block **block_p)
 {
     tng_gen_block_t block;
 
-    *block_p = malloc(sizeof(struct tng_gen_block));
+    *block_p = (struct tng_gen_block *)malloc(sizeof(struct tng_gen_block));
     if(!*block_p)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIuPTR" bytes). %s: %d\n",
-               sizeof(struct tng_gen_block), __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
         return(TNG_CRITICAL);
     }
 
@@ -1102,7 +1098,7 @@ static tng_function_status tng_block_header_read
     }
 
     if(tng_data->input_endianness_swap_func_64 &&
-       tng_data->input_endianness_swap_func_64(tng_data, &block->header_contents_size) != TNG_SUCCESS)
+       tng_data->input_endianness_swap_func_64(tng_data, (uint64_t *)&block->header_contents_size) != TNG_SUCCESS)
     {
         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
                 __FILE__, __LINE__);
@@ -1204,11 +1200,10 @@ static tng_function_status tng_md5_hash_update(const tng_trajectory_t tng_data,
         free(block->block_contents);
     }
 
-    block->block_contents = malloc(block->block_contents_size);
+    block->block_contents = (char *)malloc(block->block_contents_size);
     if(!block->block_contents)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
-               block->block_contents_size, __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
         return(TNG_CRITICAL);
     }
 
@@ -1243,7 +1238,7 @@ static tng_function_status tng_header_pointers_update
 {
     tng_gen_block_t block;
     FILE *temp = tng_data->input_file;
-    int64_t output_file_pos, pos, contents_start_pos;
+    uint64_t output_file_pos, pos, contents_start_pos;
 
     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
     {
@@ -1342,7 +1337,7 @@ static tng_function_status tng_frame_set_pointers_update
     tng_gen_block_t block;
     tng_trajectory_frame_set_t frame_set;
     FILE *temp = tng_data->input_file;
-    int64_t pos, output_file_pos, contents_start_pos;
+    uint64_t pos, output_file_pos, contents_start_pos;
 
     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
     {
@@ -1658,7 +1653,7 @@ static tng_function_status tng_reread_frame_set_at_file_pos
         stat = tng_block_header_read(tng_data, block);
         if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
         {
-            fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
+            fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", pos,
                     __FILE__, __LINE__);
             tng_block_destroy(&block);
             return(TNG_FAILURE);
@@ -1704,7 +1699,7 @@ static tng_function_status tng_file_pos_of_subsequent_trajectory_block_get
     stat = tng_block_header_read(tng_data, block);
     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
     {
-        fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", *pos,
+        fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", *pos,
                 __FILE__, __LINE__);
         tng_block_destroy(&block);
         return(TNG_FAILURE);
@@ -1724,7 +1719,7 @@ static tng_function_status tng_file_pos_of_subsequent_trajectory_block_get
         stat = tng_block_header_read(tng_data, block);
         if(stat == TNG_CRITICAL)
         {
-            fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", *pos,
+            fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", *pos,
                     __FILE__, __LINE__);
             tng_block_destroy(&block);
             return(TNG_CRITICAL);
@@ -1784,11 +1779,10 @@ static tng_function_status tng_frame_set_complete_migrate
 
     fseeko(tng_data->input_file, block_start_pos, SEEK_SET);
 
-    contents = malloc(block_len);
+    contents = (char *)malloc(block_len);
     if(!contents)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
-                block_len, __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
         return(TNG_CRITICAL);
     }
 
@@ -1810,6 +1804,10 @@ static tng_function_status tng_frame_set_complete_migrate
     }
 
     tng_data->current_trajectory_frame_set_output_file_pos = new_pos;
+    if(tng_data->input_file == tng_data->output_file)
+    {
+        tng_data->current_trajectory_frame_set_input_file_pos = new_pos;
+    }
 
     tng_frame_set_pointers_update(tng_data, hash_mode);
 
@@ -1861,7 +1859,7 @@ static tng_function_status tng_length_of_current_frame_set_contents_get
     stat = tng_block_header_read(tng_data, block);
     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
     {
-        fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+        fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                 curr_frame_set_pos, __FILE__, __LINE__);
         tng_block_destroy(&block);
         return(TNG_FAILURE);
@@ -1991,10 +1989,10 @@ static tng_function_status tng_block_header_len_calculate
      * termination */
     if(!block->name)
     {
-        block->name = malloc(1);
+        block->name = (char *)malloc(1);
         if(!block->name)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
@@ -2100,10 +2098,10 @@ static tng_function_status tng_general_info_block_len_calculate
      * termination */
     if(!tng_data->first_program_name)
     {
-        tng_data->first_program_name = malloc(1);
+        tng_data->first_program_name = (char *)malloc(1);
         if(!tng_data->first_program_name)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
@@ -2111,10 +2109,10 @@ static tng_function_status tng_general_info_block_len_calculate
     }
     if(!tng_data->last_program_name)
     {
-        tng_data->last_program_name = malloc(1);
+        tng_data->last_program_name = (char *)malloc(1);
         if(!tng_data->last_program_name)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
@@ -2122,10 +2120,10 @@ static tng_function_status tng_general_info_block_len_calculate
     }
     if(!tng_data->first_user_name)
     {
-        tng_data->first_user_name = malloc(1);
+        tng_data->first_user_name = (char *)malloc(1);
         if(!tng_data->first_user_name)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
@@ -2133,10 +2131,10 @@ static tng_function_status tng_general_info_block_len_calculate
     }
     if(!tng_data->last_user_name)
     {
-        tng_data->last_user_name = malloc(1);
+        tng_data->last_user_name = (char *)malloc(1);
         if(!tng_data->last_user_name)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
@@ -2144,10 +2142,10 @@ static tng_function_status tng_general_info_block_len_calculate
     }
     if(!tng_data->first_computer_name)
     {
-        tng_data->first_computer_name = malloc(1);
+        tng_data->first_computer_name = (char *)malloc(1);
         if(!tng_data->first_computer_name)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
@@ -2155,10 +2153,10 @@ static tng_function_status tng_general_info_block_len_calculate
     }
     if(!tng_data->last_computer_name)
     {
-        tng_data->last_computer_name = malloc(1);
+        tng_data->last_computer_name = (char *)malloc(1);
         if(!tng_data->last_computer_name)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
@@ -2166,10 +2164,10 @@ static tng_function_status tng_general_info_block_len_calculate
     }
     if(!tng_data->first_pgp_signature)
     {
-        tng_data->first_pgp_signature = malloc(1);
+        tng_data->first_pgp_signature = (char *)malloc(1);
         if(!tng_data->first_pgp_signature)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
@@ -2177,10 +2175,10 @@ static tng_function_status tng_general_info_block_len_calculate
     }
     if(!tng_data->last_pgp_signature)
     {
-        tng_data->last_pgp_signature = malloc(1);
+        tng_data->last_pgp_signature = (char *)malloc(1);
         if(!tng_data->last_pgp_signature)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
@@ -2188,10 +2186,10 @@ static tng_function_status tng_general_info_block_len_calculate
     }
     if(!tng_data->forcefield_name)
     {
-        tng_data->forcefield_name = malloc(1);
+        tng_data->forcefield_name = (char *)malloc(1);
         if(!tng_data->forcefield_name)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
@@ -2410,11 +2408,10 @@ static tng_function_status tng_general_info_block_write
 
     name_len = strlen("GENERAL INFO");
 
-    block->name = malloc(name_len + 1);
+    block->name = (char *)malloc(name_len + 1);
     if(!block->name)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%u bytes). %s: %d\n",
-                (unsigned int)(name_len+1), __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
         tng_block_destroy(&block);
         return(TNG_CRITICAL);
     }
@@ -2797,10 +2794,10 @@ static tng_function_status tng_molecules_block_len_calculate
         molecule = &tng_data->molecules[i];
         if(!molecule->name)
         {
-            molecule->name = malloc(1);
+            molecule->name = (char *)malloc(1);
             if(!molecule->name)
             {
-                fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+                fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
                        __FILE__, __LINE__);
                 return(TNG_CRITICAL);
             }
@@ -2815,10 +2812,10 @@ static tng_function_status tng_molecules_block_len_calculate
 
             if(!chain->name)
             {
-                chain->name = malloc(1);
+                chain->name = (char *)malloc(1);
                 if(!chain->name)
                 {
-                    fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+                    fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
                            __FILE__, __LINE__);
                     return(TNG_CRITICAL);
                 }
@@ -2838,10 +2835,10 @@ static tng_function_status tng_molecules_block_len_calculate
 
             if(!residue->name)
             {
-                residue->name = malloc(1);
+                residue->name = (char *)malloc(1);
                 if(!residue->name)
                 {
-                    fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+                    fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
                            __FILE__, __LINE__);
                     return(TNG_CRITICAL);
                 }
@@ -2860,10 +2857,10 @@ static tng_function_status tng_molecules_block_len_calculate
             *len += sizeof(atom->id);
             if(!atom->name)
             {
-                atom->name = malloc(1);
+                atom->name = (char *)malloc(1);
                 if(!atom->name)
                 {
-                    fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+                    fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
                            __FILE__, __LINE__);
                     return(TNG_CRITICAL);
                 }
@@ -2873,10 +2870,10 @@ static tng_function_status tng_molecules_block_len_calculate
 
             if(!atom->atom_type)
             {
-                atom->atom_type = malloc(1);
+                atom->atom_type = (char *)malloc(1);
                 if(!atom->atom_type)
                 {
-                    fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+                    fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
                            __FILE__, __LINE__);
                     return(TNG_CRITICAL);
                 }
@@ -2973,13 +2970,11 @@ static tng_function_status tng_molecules_block_read
 
     tng_data->n_particles = 0;
 
-    tng_data->molecules = malloc(tng_data->n_molecules *
-                          sizeof(struct tng_molecule));
+    tng_data->molecules = (struct tng_molecule *)malloc(tng_data->n_molecules *
+                                                        sizeof(struct tng_molecule));
     if(!tng_data->molecules)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-               tng_data->n_molecules * sizeof(struct tng_molecule),
-               __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
         return(TNG_CRITICAL);
     }
 
@@ -2989,13 +2984,11 @@ static tng_function_status tng_molecules_block_read
         {
             free(tng_data->molecule_cnt_list);
         }
-        tng_data->molecule_cnt_list = malloc(sizeof(int64_t) *
-                                      tng_data->n_molecules);
+        tng_data->molecule_cnt_list = (int64_t *)malloc(sizeof(int64_t) *
+                                                        tng_data->n_molecules);
         if(!tng_data->molecule_cnt_list)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-                   tng_data->n_molecules * sizeof(struct tng_molecule),
-                   __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
     }
@@ -3014,7 +3007,7 @@ static tng_function_status tng_molecules_block_read
             return(TNG_CRITICAL);
         }
 
-/*         fprintf(stderr, "TNG library: Read id: %"PRId64" offset: %d\n", molecule->id, offset);*/
+/*         fprintf(stderr, "TNG library: Read id: %" PRId64 " offset: %d\n", molecule->id, offset);*/
         tng_freadstr(tng_data, &molecule->name, hash_mode, &md5_state, __LINE__);
 
         if(tng_file_input_numerical(tng_data, &molecule->quaternary_str,
@@ -3060,13 +3053,12 @@ static tng_function_status tng_molecules_block_read
 
         if(molecule->n_chains > 0)
         {
-            molecule->chains = malloc(molecule->n_chains *
-                                    sizeof(struct tng_chain));
+            molecule->chains = (struct tng_chain *)malloc(molecule->n_chains *
+                                                          sizeof(struct tng_chain));
             if(!molecule->chains)
             {
-                fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-                    molecule->n_chains * sizeof(struct tng_chain),
-                    __FILE__, __LINE__);
+                fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                        __FILE__, __LINE__);
                 return(TNG_CRITICAL);
             }
 
@@ -3079,13 +3071,12 @@ static tng_function_status tng_molecules_block_read
 
         if(molecule->n_residues > 0)
         {
-            molecule->residues = malloc(molecule->n_residues *
-                                        sizeof(struct tng_residue));
+            molecule->residues = (struct tng_residue *)malloc(molecule->n_residues *
+                                                              sizeof(struct tng_residue));
             if(!molecule->residues)
             {
-                fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-                    molecule->n_residues * sizeof(struct tng_residue),
-                    __FILE__, __LINE__);
+                fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                        __FILE__, __LINE__);
                 if(molecule->chains)
                 {
                     free(molecule->chains);
@@ -3101,13 +3092,12 @@ static tng_function_status tng_molecules_block_read
             residue = 0;
         }
 
-        molecule->atoms = malloc(molecule->n_atoms *
-                                 sizeof(struct tng_atom));
+        molecule->atoms = (struct tng_atom *)malloc(molecule->n_atoms *
+                                                 sizeof(struct tng_atom));
         if(!molecule->atoms)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-                   molecule->n_atoms * sizeof(struct tng_atom),
-                   __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             if(molecule->chains)
             {
                 free(molecule->chains);
@@ -3221,13 +3211,12 @@ static tng_function_status tng_molecules_block_read
 
         if(molecule->n_bonds > 0)
         {
-            tng_data->molecules[i].bonds = malloc(molecule->n_bonds *
-                                           sizeof(struct tng_bond));
+            tng_data->molecules[i].bonds = (struct tng_bond *)malloc(molecule->n_bonds *
+                                                                     sizeof(struct tng_bond));
             if(!molecule->bonds)
             {
-                fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-                       molecule->n_bonds * sizeof(struct tng_bond),
-                       __FILE__, __LINE__);
+                fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                        __FILE__, __LINE__);
                 if(molecule->chains)
                 {
                     free(molecule->chains);
@@ -3330,11 +3319,10 @@ static tng_function_status tng_molecules_block_write
 
     name_len = (unsigned int)strlen("MOLECULES");
 
-    block->name = malloc(name_len + 1);
+    block->name = (char *)malloc(name_len + 1);
     if(!block->name)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
-                name_len+1, __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
         tng_block_destroy(&block);
         return(TNG_CRITICAL);
     }
@@ -3607,13 +3595,12 @@ static tng_function_status tng_frame_set_block_read
         if(!frame_set->molecule_cnt_list)
         {
                 frame_set->molecule_cnt_list =
-                malloc(sizeof(int64_t) * tng_data->n_molecules);
+                (int64_t *)malloc(sizeof(int64_t) * tng_data->n_molecules);
 
                 if(!frame_set->molecule_cnt_list)
                 {
-                    fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-                           sizeof(int64_t) * tng_data->n_molecules,
-                           __FILE__, __LINE__);
+                    fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                            __FILE__, __LINE__);
                     return(TNG_CRITICAL);
                 }
         }
@@ -3710,7 +3697,7 @@ static tng_function_status tng_frame_set_block_read
         {
             if(strncmp(block->md5_hash, hash, TNG_MD5_HASH_LEN) != 0)
             {
-                fprintf(stderr, "TNG library: Frame set block contents corrupt (first frame %"PRId64"). Hashes do not match. "
+                fprintf(stderr, "TNG library: Frame set block contents corrupt (first frame %" PRId64 "). Hashes do not match. "
                         "%s: %d\n", frame_set->first_frame, __FILE__, __LINE__);
             }
         }
@@ -3763,11 +3750,11 @@ static tng_function_status tng_frame_set_block_write
 
     if(!block->name || strlen(block->name) < name_len)
     {
-        temp_name = realloc(block->name, name_len + 1);
+        temp_name = (char *)realloc(block->name, name_len + 1);
         if(!temp_name)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%u bytes). %s: %d\n",
-                   name_len+1, __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             free(block->name);
             block->name = 0;
             return(TNG_CRITICAL);
@@ -3943,13 +3930,13 @@ static tng_function_status tng_trajectory_mapping_block_read
      * size or if the contents can be read. */
 
     frame_set->n_mapping_blocks++;
-    mappings = realloc(frame_set->mappings,
-                       sizeof(struct tng_particle_mapping) *
-                       frame_set->n_mapping_blocks);
+    mappings = (tng_particle_mapping_t)realloc(frame_set->mappings,
+                                               sizeof(struct tng_particle_mapping) *
+                                               frame_set->n_mapping_blocks);
     if(!mappings)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
-               block->block_contents_size, __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         free(frame_set->mappings);
         frame_set->mappings = 0;
         return(TNG_CRITICAL);
@@ -3977,12 +3964,12 @@ static tng_function_status tng_trajectory_mapping_block_read
         return(TNG_CRITICAL);
     }
 
-    mapping->real_particle_numbers = malloc(mapping->n_particles *
-                                            sizeof(int64_t));
+    mapping->real_particle_numbers = (int64_t *)malloc(mapping->n_particles *
+                                                       sizeof(int64_t));
     if(!mapping->real_particle_numbers)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-                mapping->n_particles * sizeof(int64_t), __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         return(TNG_CRITICAL);
     }
 
@@ -4081,11 +4068,11 @@ static tng_function_status tng_trajectory_mapping_block_write
 
     if(!block->name || strlen(block->name) < name_len)
     {
-        temp_name = realloc(block->name, name_len + 1);
+        temp_name = (char *)realloc(block->name, name_len + 1);
         if(!temp_name)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%u bytes). %s: %d\n",
-                   name_len+1, __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             free(block->name);
             block->name = 0;
             return(TNG_CRITICAL);
@@ -4198,15 +4185,13 @@ static tng_function_status tng_particle_data_block_create
     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
     {
         frame_set->n_particle_data_blocks++;
-        data = realloc(frame_set->tr_particle_data,
-                    sizeof(struct tng_data) *
-                    frame_set->n_particle_data_blocks);
+        data = (tng_data_t)realloc(frame_set->tr_particle_data,
+                                   sizeof(struct tng_data) *
+                                   frame_set->n_particle_data_blocks);
         if(!data)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIuPTR" bytes). %s: %d\n",
-                sizeof(struct tng_data) *
-                frame_set->n_particle_data_blocks,
-                __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             free(frame_set->tr_particle_data);
             frame_set->tr_particle_data = 0;
             return(TNG_CRITICAL);
@@ -4216,14 +4201,12 @@ static tng_function_status tng_particle_data_block_create
     else
     {
         tng_data->n_particle_data_blocks++;
-        data = realloc(tng_data->non_tr_particle_data,
-                        sizeof(struct tng_data) *
-                        tng_data->n_particle_data_blocks);
+        data = (tng_data_t)realloc(tng_data->non_tr_particle_data,
+                                   sizeof(struct tng_data) *
+                                   tng_data->n_particle_data_blocks);
         if(!data)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIuPTR" bytes). %s: %d\n",
-                    sizeof(struct tng_data) *
-                    tng_data->n_particle_data_blocks,
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
                     __FILE__, __LINE__);
             free(tng_data->non_tr_particle_data);
             tng_data->non_tr_particle_data = 0;
@@ -4282,7 +4265,7 @@ static tng_function_status tng_compress(const tng_trajectory_t tng_data,
         if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
         {
             nalgo = tng_compress_nalgo();
-            alt_algo = malloc(nalgo * sizeof *tng_data->compress_algo_pos);
+            alt_algo = (int *)malloc(nalgo * sizeof *tng_data->compress_algo_pos);
 
             /* If we have already determined the initial coding and
              * initial coding parameter do not determine them again. */
@@ -4325,8 +4308,8 @@ static tng_function_status tng_compress(const tng_trajectory_t tng_data,
             if(!tng_data->compress_algo_pos)
             {
                 nalgo = tng_compress_nalgo();
-                tng_data->compress_algo_pos=malloc(nalgo *
-                                                   sizeof *tng_data->compress_algo_pos);
+                tng_data->compress_algo_pos = (int *)malloc(nalgo *
+                                                            sizeof *tng_data->compress_algo_pos);
                 tng_data->compress_algo_pos[0] = alt_algo[0];
                 tng_data->compress_algo_pos[1] = alt_algo[1];
                 tng_data->compress_algo_pos[2] = -1;
@@ -4350,8 +4333,8 @@ static tng_function_status tng_compress(const tng_trajectory_t tng_data,
             if(!tng_data->compress_algo_pos)
             {
                 nalgo = tng_compress_nalgo();
-                tng_data->compress_algo_pos=malloc(nalgo *
-                                                   sizeof *tng_data->compress_algo_pos);
+                tng_data->compress_algo_pos = (int *)malloc(nalgo *
+                                                            sizeof *tng_data->compress_algo_pos);
                 tng_data->compress_algo_pos[0] = -1;
                 tng_data->compress_algo_pos[1] = -1;
                 tng_data->compress_algo_pos[2] = -1;
@@ -4423,7 +4406,7 @@ static tng_function_status tng_compress(const tng_trajectory_t tng_data,
         if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
         {
             nalgo = tng_compress_nalgo();
-            alt_algo=malloc(nalgo * sizeof *tng_data->compress_algo_vel);
+            alt_algo = (int *)malloc(nalgo * sizeof *tng_data->compress_algo_vel);
 
             /* If we have already determined the initial coding and
              * initial coding parameter do not determine them again. */
@@ -4466,8 +4449,8 @@ static tng_function_status tng_compress(const tng_trajectory_t tng_data,
             if(!tng_data->compress_algo_vel)
             {
                 nalgo = tng_compress_nalgo();
-                tng_data->compress_algo_vel=malloc(nalgo *
-                                                   sizeof *tng_data->compress_algo_vel);
+                tng_data->compress_algo_vel = (int *)malloc(nalgo *
+                                                            sizeof *tng_data->compress_algo_vel);
                 tng_data->compress_algo_vel[0] = alt_algo[0];
                 tng_data->compress_algo_vel[1] = alt_algo[1];
                 tng_data->compress_algo_vel[2] = -1;
@@ -4491,8 +4474,8 @@ static tng_function_status tng_compress(const tng_trajectory_t tng_data,
             if(!tng_data->compress_algo_vel)
             {
                 nalgo = tng_compress_nalgo();
-                tng_data->compress_algo_vel=malloc(nalgo *
-                                                   sizeof *tng_data->compress_algo_vel);
+                tng_data->compress_algo_vel = (int *)malloc(nalgo *
+                                                            sizeof *tng_data->compress_algo_vel);
                 tng_data->compress_algo_vel[0] = -1;
                 tng_data->compress_algo_vel[1] = -1;
                 tng_data->compress_algo_vel[2] = -1;
@@ -4605,11 +4588,11 @@ static tng_function_status tng_uncompress(const tng_trajectory_t tng_data,
 
     if(type == TNG_FLOAT_DATA)
     {
-        f_dest = malloc(uncompressed_len);
+        f_dest = (float *)malloc(uncompressed_len);
         if(!f_dest)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
-                uncompressed_len, __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
         result = tng_compress_uncompress_float(*data, f_dest);
@@ -4620,11 +4603,11 @@ static tng_function_status tng_uncompress(const tng_trajectory_t tng_data,
     }
     else
     {
-        d_dest = malloc(uncompressed_len);
+        d_dest = (double *)malloc(uncompressed_len);
         if(!d_dest)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
-                uncompressed_len, __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
         result = tng_compress_uncompress(*data, d_dest);
@@ -4643,7 +4626,6 @@ static tng_function_status tng_uncompress(const tng_trajectory_t tng_data,
     return(TNG_SUCCESS);
 }
 
-#ifdef USE_ZLIB
 static tng_function_status tng_gzip_compress(const tng_trajectory_t tng_data,
                                              char **data, const int64_t len,
                                              int64_t *new_len)
@@ -4653,11 +4635,11 @@ static tng_function_status tng_gzip_compress(const tng_trajectory_t tng_data,
     (void)tng_data;
 
     max_len = compressBound(len);
-    dest = malloc(max_len);
+    dest = (Bytef *)malloc(max_len);
     if(!dest)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
-               max_len, __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         return(TNG_CRITICAL);
     }
 
@@ -4696,11 +4678,11 @@ static tng_function_status tng_gzip_uncompress(const tng_trajectory_t tng_data,
     (void)tng_data;
     uLongf new_len = uncompressed_len;
 
-    dest = malloc(uncompressed_len);
+    dest = (Bytef *)malloc(uncompressed_len);
     if(!dest)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
-               uncompressed_len, __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         return(TNG_CRITICAL);
     }
 
@@ -4733,7 +4715,6 @@ static tng_function_status tng_gzip_uncompress(const tng_trajectory_t tng_data,
 
     return(TNG_SUCCESS);
 }
-#endif
 
 /**
  * @brief Allocate memory for storing particle data.
@@ -4792,27 +4773,25 @@ static tng_function_status tng_allocate_particle_data_mem
 
     if(data->datatype == TNG_CHAR_DATA)
     {
-        data->strings = malloc(sizeof(char ***) * frame_alloc);
+        data->strings = (char ****)malloc(sizeof(char ***) * frame_alloc);
         for(i = 0; i < frame_alloc; i++)
         {
-            data->strings[i] = malloc(sizeof(char **) *
+            data->strings[i] = (char ***)malloc(sizeof(char **) *
                                     n_particles);
             if(!data->strings[i])
             {
-                fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-                    sizeof(union data_values *) * n_particles,
-                    __FILE__, __LINE__);
+                fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                        __FILE__, __LINE__);
                 return(TNG_CRITICAL);
             }
             for(j = 0; j < n_particles; j++)
             {
-                data->strings[i][j] = malloc(sizeof(char *) *
+                data->strings[i][j] = (char **)malloc(sizeof(char *) *
                                             n_values_per_frame);
                 if(!data->strings[i][j])
                 {
-                    fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-                        sizeof(union data_values) * n_values_per_frame,
-                        __FILE__, __LINE__);
+                    fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                            __FILE__, __LINE__);
                     return(TNG_CRITICAL);
                 }
                 for(k = 0; k < n_values_per_frame; k++)
@@ -4837,15 +4816,13 @@ static tng_function_status tng_allocate_particle_data_mem
             size = sizeof(double);
         }
 
-        values = realloc(data->values,
-                         size * frame_alloc *
-                         n_particles * n_values_per_frame);
+        values = (void ***)realloc(data->values,
+                                   size * frame_alloc *
+                                   n_particles * n_values_per_frame);
         if(!values)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
-                   size * frame_alloc *
-                   n_particles * n_values_per_frame,
-                   __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             free(data->values);
             data->values = 0;
             return(TNG_CRITICAL);
@@ -5093,13 +5070,12 @@ static tng_function_status tng_data_block_create
     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
     {
         frame_set->n_data_blocks++;
-        data = realloc(frame_set->tr_data, sizeof(struct tng_data) *
-                       frame_set->n_data_blocks);
+        data = (tng_data_t)realloc(frame_set->tr_data, sizeof(struct tng_data) *
+                                   frame_set->n_data_blocks);
         if(!data)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIuPTR" bytes). %s: %d\n",
-                sizeof(struct tng_data) * frame_set->n_data_blocks,
-                __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             free(frame_set->tr_data);
             frame_set->tr_data = 0;
             return(TNG_CRITICAL);
@@ -5109,13 +5085,12 @@ static tng_function_status tng_data_block_create
     else
     {
         tng_data->n_data_blocks++;
-        data = realloc(tng_data->non_tr_data, sizeof(struct tng_data) *
-                        tng_data->n_data_blocks);
+        data = (tng_data_t)realloc(tng_data->non_tr_data, sizeof(struct tng_data) *
+                                   tng_data->n_data_blocks);
         if(!data)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIuPTR" bytes). %s: %d\n",
-                sizeof(struct tng_data) * tng_data->n_data_blocks,
-                __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             free(tng_data->non_tr_data);
             tng_data->non_tr_data = 0;
             return(TNG_CRITICAL);
@@ -5181,16 +5156,15 @@ static tng_function_status tng_allocate_data_mem
 
     if(data->datatype == TNG_CHAR_DATA)
     {
-        data->strings = malloc(sizeof(char ***));
-        data->strings[0] = malloc(sizeof(char **) * frame_alloc);
+        data->strings = (char ****)malloc(sizeof(char ***));
+        data->strings[0] = (char ***)malloc(sizeof(char **) * frame_alloc);
         for(i = 0; i < frame_alloc; i++)
         {
-            data->strings[0][i] = malloc(sizeof(char *) * n_values_per_frame);
+            data->strings[0][i] = (char **)malloc(sizeof(char *) * n_values_per_frame);
             if(!data->strings[0][i])
             {
-                fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
-                       n_values_per_frame,
-                       __FILE__, __LINE__);
+                fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                        __FILE__, __LINE__);
                 return(TNG_CRITICAL);
             }
             for(j = 0; j < n_values_per_frame; j++)
@@ -5214,15 +5188,13 @@ static tng_function_status tng_allocate_data_mem
             size = sizeof(double);
         }
 
-        values = realloc(data->values,
-                         size * frame_alloc *
-                         n_values_per_frame);
+        values = (void **)realloc(data->values,
+                                  size * frame_alloc *
+                                  n_values_per_frame);
         if(!values)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
-                   size * frame_alloc *
-                   n_values_per_frame,
-                   __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             free(data->values);
             data->values = 0;
             return(TNG_CRITICAL);
@@ -5290,16 +5262,6 @@ static tng_function_status tng_data_read(const tng_trajectory_t tng_data,
 
 /*     fprintf(stderr, "TNG library: %s\n", block->name);*/
 
-    /* This must be caught early to avoid creating a data block if not necessary. */
-#ifndef USE_ZLIB
-    if(codec_id == TNG_GZIP_COMPRESSION)
-    {
-        fprintf(stderr, "TNG library: Cannot uncompress data block. %s: %d\n", __FILE__,
-                __LINE__);
-        return(TNG_FAILURE);
-    }
-#endif
-
     switch(datatype)
     {
     case TNG_CHAR_DATA:
@@ -5395,11 +5357,11 @@ static tng_function_status tng_data_read(const tng_trajectory_t tng_data,
 
         data->block_id = block->id;
 
-        data->block_name = malloc(strlen(block->name) + 1);
+        data->block_name = (char *)malloc(strlen(block->name) + 1);
         if(!data->block_name)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n",
-                   (unsigned int)strlen(block->name)+1, __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
         strcpy(data->block_name, block->name);
@@ -5448,11 +5410,11 @@ static tng_function_status tng_data_read(const tng_trajectory_t tng_data,
 
     n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
 
-    contents = malloc(block_data_len);
+    contents = (char *)malloc(block_data_len);
     if(!contents)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
-                block_data_len, __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         return(TNG_CRITICAL);
     }
 
@@ -5480,7 +5442,7 @@ static tng_function_status tng_data_read(const tng_trajectory_t tng_data,
             fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
             break;
         case TNG_TNG_COMPRESSION:
-/*            fprintf(stderr, "TNG library: Before TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
+/*            fprintf(stderr, "TNG library: Before TNG uncompression: %" PRId64 "\n", block->block_contents_size);*/
             if(tng_uncompress(tng_data, block, datatype,
                               &contents, full_data_len) != TNG_SUCCESS)
             {
@@ -5489,11 +5451,10 @@ static tng_function_status tng_data_read(const tng_trajectory_t tng_data,
                 free(contents);
                 return(TNG_CRITICAL);
             }
-/*            fprintf(stderr, "TNG library: After TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
+/*            fprintf(stderr, "TNG library: After TNG uncompression: %" PRId64 "\n", block->block_contents_size);*/
             break;
-#ifdef USE_ZLIB
         case TNG_GZIP_COMPRESSION:
-    /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
+    /*         fprintf(stderr, "TNG library: Before compression: %" PRId64 "\n", block->block_contents_size); */
             if(tng_gzip_uncompress(tng_data, &contents,
                                    block_data_len, full_data_len) != TNG_SUCCESS)
             {
@@ -5502,9 +5463,8 @@ static tng_function_status tng_data_read(const tng_trajectory_t tng_data,
                 free(contents);
                 return(TNG_CRITICAL);
             }
-    /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
+    /*         fprintf(stderr, "TNG library: After compression: %" PRId64 "\n", block->block_contents_size); */
             break;
-#endif
         }
     }
     else
@@ -5560,11 +5520,11 @@ static tng_function_status tng_data_read(const tng_trajectory_t tng_data,
                         {
                             free(second_dim_values[k]);
                         }
-                        second_dim_values[k] = malloc(len);
+                        second_dim_values[k] = (char *)malloc(len);
                         if(!second_dim_values[k])
                         {
-                            fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
-                                len, __FILE__, __LINE__);
+                            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                                    __FILE__, __LINE__);
                             free(contents);
                             return(TNG_CRITICAL);
                         }
@@ -5586,11 +5546,11 @@ static tng_function_status tng_data_read(const tng_trajectory_t tng_data,
                     {
                         free(data->strings[0][i][j]);
                     }
-                    data->strings[0][i][j] = malloc(len);
+                    data->strings[0][i][j] = (char *)malloc(len);
                     if(!data->strings[0][i][j])
                     {
-                        fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
-                               len, __FILE__, __LINE__);
+                        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                                __FILE__, __LINE__);
                         free(contents);
                         return(TNG_CRITICAL);
                     }
@@ -5623,7 +5583,7 @@ static tng_function_status tng_data_read(const tng_trajectory_t tng_data,
                     for(i = 0; i < full_data_len; i+=size)
                     {
                         if(tng_data->input_endianness_swap_func_32(tng_data,
-                            (int32_t *)((char *)data->values + i))
+                            (uint32_t *)((char *)data->values + i))
                             != TNG_SUCCESS)
                         {
                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
@@ -5639,7 +5599,7 @@ static tng_function_status tng_data_read(const tng_trajectory_t tng_data,
                     for(i = 0; i < full_data_len; i+=size)
                     {
                         if(tng_data->input_endianness_swap_func_64(tng_data,
-                            (int64_t *)((char *)data->values + i))
+                            (uint64_t *)((char *)data->values + i))
                             != TNG_SUCCESS)
                         {
                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
@@ -5774,10 +5734,10 @@ static tng_function_status tng_data_block_write(const tng_trajectory_t tng_data,
 
     if(!block->name || strlen(block->name) < len)
     {
-        temp_name = realloc(block->name, len);
+        temp_name = (char *)realloc(block->name, len);
         if(!temp_name)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIuPTR" bytes). %s: %d\n", len+1,
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
                    __FILE__, __LINE__);
             free(block->name);
             block->name = 0;
@@ -6024,11 +5984,11 @@ static tng_function_status tng_data_block_write(const tng_trajectory_t tng_data,
         {
             full_data_len = size * frame_step * data->n_values_per_frame;
         }
-        contents = malloc(full_data_len);
+        contents = (char *)malloc(full_data_len);
         if(!contents)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
-                    full_data_len, __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
 
@@ -6049,7 +6009,7 @@ static tng_function_status tng_data_block_write(const tng_trajectory_t tng_data,
                             for(i = 0; i < full_data_len; i+=size)
                             {
                                 if(tng_data->output_endianness_swap_func_32(tng_data,
-                                (int32_t *)(contents + i))
+                                (uint32_t *)(contents + i))
                                 != TNG_SUCCESS)
                                 {
                                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
@@ -6064,12 +6024,12 @@ static tng_function_status tng_data_block_write(const tng_trajectory_t tng_data,
                         if(fabs(multiplier - 1.0) > 0.00001 ||
                         tng_data->output_endianness_swap_func_32)
                         {
-                            for(i = 0; full_data_len; i+=size)
+                            for(i = 0; i < full_data_len; i+=size)
                             {
                                 *(float *)(contents + i) *= (float)multiplier;
                                 if(tng_data->output_endianness_swap_func_32 &&
                                 tng_data->output_endianness_swap_func_32(tng_data,
-                                (int32_t *)(contents + i))
+                                (uint32_t *)(contents + i))
                                 != TNG_SUCCESS)
                                 {
                                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
@@ -6085,7 +6045,7 @@ static tng_function_status tng_data_block_write(const tng_trajectory_t tng_data,
                         for(i = 0; i < full_data_len; i+=size)
                         {
                             if(tng_data->output_endianness_swap_func_64(tng_data,
-                            (int64_t *)(contents + i))
+                            (uint64_t *)(contents + i))
                             != TNG_SUCCESS)
                             {
                                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
@@ -6102,7 +6062,7 @@ static tng_function_status tng_data_block_write(const tng_trajectory_t tng_data,
                             for(i = 0; i < full_data_len; i+=size)
                             {
                                 if(tng_data->output_endianness_swap_func_64(tng_data,
-                                (int64_t *)(contents + i))
+                                (uint64_t *)(contents + i))
                                 != TNG_SUCCESS)
                                 {
                                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
@@ -6122,7 +6082,7 @@ static tng_function_status tng_data_block_write(const tng_trajectory_t tng_data,
                                 *(double *)(contents + i) *= multiplier;
                                 if(tng_data->output_endianness_swap_func_64 &&
                                 tng_data->output_endianness_swap_func_64(tng_data,
-                                (int64_t *)(contents + i))
+                                (uint64_t *)(contents + i))
                                 != TNG_SUCCESS)
                                 {
                                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
@@ -6172,9 +6132,8 @@ static tng_function_status tng_data_block_write(const tng_trajectory_t tng_data,
                 return(stat);
             }
             break;
-#ifdef USE_ZLIB
         case TNG_GZIP_COMPRESSION:
-    /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
+    /*         fprintf(stderr, "TNG library: Before compression: %" PRId64 "\n", block->block_contents_size); */
             stat = tng_gzip_compress(tng_data,
                                      &contents,
                                      full_data_len,
@@ -6189,9 +6148,8 @@ static tng_function_status tng_data_block_write(const tng_trajectory_t tng_data,
                 }
                 data->codec_id = TNG_UNCOMPRESSED;
             }
-    /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
+    /*         fprintf(stderr, "TNG library: After compression: %" PRId64 "\n", block->block_contents_size); */
             break;
-#endif
         }
         if(block_data_len != full_data_len)
         {
@@ -6554,7 +6512,7 @@ static tng_function_status tng_data_block_contents_read
 //     {
 //         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
 //         {
-//             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
+//             fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", pos,
 //                    __FILE__, __LINE__);
 //             tng_data->input_file = temp;
 //             tng_block_destroy(&block);
@@ -6671,10 +6629,10 @@ static tng_function_status tng_frame_set_finalize
 //     }
 //     if(!block->name)
 //     {
-//         block->name = malloc(len);
+//         block->name = (char *)malloc(len);
 //         if(!block->name)
 //         {
-//             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
+//             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
 //                    __FILE__, __LINE__);
 //             return(TNG_CRITICAL);
 //         }
@@ -6742,11 +6700,11 @@ tng_function_status DECLSPECDLLEXPORT tng_atom_name_set
     }
     if(!atom->name)
     {
-        atom->name = malloc(len);
+        atom->name = (char *)malloc(len);
         if(!atom->name)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
-                   __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
     }
@@ -6798,11 +6756,11 @@ tng_function_status DECLSPECDLLEXPORT tng_atom_type_set
     }
     if(!atom->atom_type)
     {
-        atom->atom_type = malloc(len);
+        atom->atom_type = (char *)malloc(len);
         if(!atom->atom_type)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
-                   __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
     }
@@ -6953,29 +6911,27 @@ tng_function_status DECLSPECDLLEXPORT tng_molecule_w_id_add
     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
 
-    new_molecules = realloc(tng_data->molecules,
-                            sizeof(struct tng_molecule) *
-                            (tng_data->n_molecules + 1));
+    new_molecules = (tng_molecule_t)realloc(tng_data->molecules,
+                                            sizeof(struct tng_molecule) *
+                                            (tng_data->n_molecules + 1));
 
     if(!new_molecules)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-               sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
-               __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         free(tng_data->molecules);
         tng_data->molecules = 0;
         return(TNG_CRITICAL);
     }
 
-    new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
-                                    sizeof(int64_t) *
-                                    (tng_data->n_molecules + 1));
+    new_molecule_cnt_list = (int64_t *)realloc(tng_data->molecule_cnt_list,
+                                               sizeof(int64_t) *
+                                               (tng_data->n_molecules + 1));
 
     if(!new_molecule_cnt_list)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-               sizeof(int64_t) * (tng_data->n_molecules + 1),
-               __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         free(tng_data->molecule_cnt_list);
         tng_data->molecule_cnt_list = 0;
         free(new_molecules);
@@ -7019,29 +6975,27 @@ tng_function_status DECLSPECDLLEXPORT tng_molecule_existing_add
         id = 1;
     }
 
-    new_molecules = realloc(tng_data->molecules,
-                            sizeof(struct tng_molecule) *
-                            (tng_data->n_molecules + 1));
+    new_molecules = (tng_molecule_t)realloc(tng_data->molecules,
+                                            sizeof(struct tng_molecule) *
+                                            (tng_data->n_molecules + 1));
 
     if(!new_molecules)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-               sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
-               __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         free(tng_data->molecules);
         tng_data->molecules = 0;
         return(TNG_CRITICAL);
     }
 
-    new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
-                                    sizeof(int64_t) *
-                                    (tng_data->n_molecules + 1));
+    new_molecule_cnt_list = (int64_t *)realloc(tng_data->molecule_cnt_list,
+                                               sizeof(int64_t) *
+                                               (tng_data->n_molecules + 1));
 
     if(!new_molecule_cnt_list)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-               sizeof(int64_t) * (tng_data->n_molecules + 1),
-               __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         free(tng_data->molecule_cnt_list);
         tng_data->molecule_cnt_list = 0;
         free(new_molecules);
@@ -7111,11 +7065,11 @@ tng_function_status DECLSPECDLLEXPORT tng_molecule_name_set
     }
     if(!molecule->name)
     {
-        molecule->name = malloc(len);
+        molecule->name = (char *)malloc(len);
         if(!molecule->name)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
-                   __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
     }
@@ -7266,24 +7220,22 @@ tng_function_status DECLSPECDLLEXPORT tng_molecule_system_copy(const tng_traject
     tng_data_dest->n_molecules = 0;
     tng_data_dest->n_particles = 0;
 
-    molecule_temp = realloc(tng_data_dest->molecules,
-                    sizeof(struct tng_molecule) * tng_data_src->n_molecules);
+    molecule_temp = (tng_molecule_t)realloc(tng_data_dest->molecules,
+                                            sizeof(struct tng_molecule) * tng_data_src->n_molecules);
     if(!molecule_temp)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-               sizeof(struct tng_molecule) * tng_data_src->n_molecules,
-               __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         free(tng_data_dest->molecules);
         tng_data_dest->molecules = 0;
         return(TNG_CRITICAL);
     }
-    list_temp = realloc(tng_data_dest->molecule_cnt_list,
-                                     sizeof(int64_t) * tng_data_src->n_molecules);
+    list_temp = (int64_t *)realloc(tng_data_dest->molecule_cnt_list,
+                                   sizeof(int64_t) * tng_data_src->n_molecules);
     if(!list_temp)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-               sizeof(int64_t) * tng_data_src->n_molecules,
-               __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         free(tng_data_dest->molecule_cnt_list);
         tng_data_dest->molecule_cnt_list = 0;
         free(molecule_temp);
@@ -7347,13 +7299,12 @@ tng_function_status DECLSPECDLLEXPORT tng_molecule_system_copy(const tng_traject
         molecule_temp->n_bonds = molecule->n_bonds;
         if(molecule->n_bonds > 0)
         {
-            bond_temp = realloc(molecule_temp->bonds, sizeof(struct tng_bond) *
-                                molecule->n_bonds);
+            bond_temp = (tng_bond_t)realloc(molecule_temp->bonds, sizeof(struct tng_bond) *
+                                            molecule->n_bonds);
             if(!bond_temp)
             {
-                fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-                       sizeof(struct tng_bond) * molecule->n_bonds,
-                       __FILE__, __LINE__);
+                fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                        __FILE__, __LINE__);
                 free(molecule_temp->bonds);
                 molecule_temp->n_bonds = 0;
                 return(TNG_CRITICAL);
@@ -7545,15 +7496,14 @@ tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_w_id_add
     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
 
-    new_chains = realloc(molecule->chains,
-                         sizeof(struct tng_chain) *
-                         (molecule->n_chains + 1));
+    new_chains = (tng_chain_t)realloc(molecule->chains,
+                                      sizeof(struct tng_chain) *
+                                      (molecule->n_chains + 1));
 
     if(!new_chains)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-               sizeof(struct tng_chain) * (molecule->n_chains + 1),
-               __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         free(molecule->chains);
         molecule->chains = 0;
         return(TNG_CRITICAL);
@@ -7586,15 +7536,14 @@ tng_function_status DECLSPECDLLEXPORT tng_molecule_bond_add
     tng_bond_t new_bonds;
     (void)tng_data;
 
-    new_bonds = realloc(molecule->bonds,
-                        sizeof(struct tng_bond) *
-                        (molecule->n_bonds + 1));
+    new_bonds = (tng_bond_t)realloc(molecule->bonds,
+                                    sizeof(struct tng_bond) *
+                                    (molecule->n_bonds + 1));
 
     if(!new_bonds)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-               sizeof(struct tng_bond) * (molecule->n_bonds + 1),
-               __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         *bond = 0;
         free(molecule->bonds);
         molecule->bonds = 0;
@@ -7684,11 +7633,11 @@ tng_function_status DECLSPECDLLEXPORT tng_chain_name_set
     }
     if(!chain->name)
     {
-        chain->name = malloc(len);
+        chain->name = (char *)malloc(len);
         if(!chain->name)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
-                   __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
     }
@@ -7811,15 +7760,14 @@ tng_function_status DECLSPECDLLEXPORT tng_chain_residue_w_id_add
         curr_index = -1;
     }
 
-    new_residues = realloc(molecule->residues,
-                           sizeof(struct tng_residue) *
-                           (molecule->n_residues + 1));
+    new_residues = (tng_residue_t)realloc(molecule->residues,
+                                          sizeof(struct tng_residue) *
+                                          (molecule->n_residues + 1));
 
     if(!new_residues)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-               sizeof(struct tng_residue) * (molecule->n_residues + 1),
-               __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         free(molecule->residues);
         molecule->residues = 0;
         return(TNG_CRITICAL);
@@ -7909,11 +7857,11 @@ tng_function_status DECLSPECDLLEXPORT tng_residue_name_set(const tng_trajectory_
     }
     if(!residue->name)
     {
-        residue->name = malloc(len);
+        residue->name = (char *)malloc(len);
         if(!residue->name)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
-                   __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
     }
@@ -8016,15 +7964,14 @@ tng_function_status DECLSPECDLLEXPORT tng_residue_atom_w_id_add
         residue->atoms_offset = molecule->n_atoms;
     }
 
-    new_atoms = realloc(molecule->atoms,
-                        sizeof(struct tng_atom) *
-                        (molecule->n_atoms + 1));
+    new_atoms = (tng_atom_t)realloc(molecule->atoms,
+                                    sizeof(struct tng_atom) *
+                                    (molecule->n_atoms + 1));
 
     if(!new_atoms)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-               sizeof(struct tng_atom) * (molecule->n_atoms + 1),
-               __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         free(molecule->atoms);
         molecule->atoms = 0;
         return(TNG_CRITICAL);
@@ -8051,11 +7998,11 @@ tng_function_status DECLSPECDLLEXPORT tng_residue_atom_w_id_add
 tng_function_status DECLSPECDLLEXPORT tng_molecule_alloc(const tng_trajectory_t tng_data,
                                                          tng_molecule_t *molecule_p)
 {
-    *molecule_p = malloc(sizeof(struct tng_molecule));
+    *molecule_p = (tng_molecule_t)malloc(sizeof(struct tng_molecule));
     if(!*molecule_p)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIuPTR" bytes). %s: %d\n",
-               sizeof(struct tng_molecule), __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         return(TNG_CRITICAL);
     }
 
@@ -8283,18 +8230,18 @@ tng_function_status DECLSPECDLLEXPORT tng_molsystem_bonds_get
         return(TNG_SUCCESS);
     }
 
-    *from_atoms = malloc(sizeof(int64_t) * (*n_bonds));
+    *from_atoms = (int64_t *)malloc(sizeof(int64_t) * (*n_bonds));
     if(!*from_atoms)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-               sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         return(TNG_CRITICAL);
     }
-    *to_atoms = malloc(sizeof(int64_t) * (*n_bonds));
+    *to_atoms = (int64_t *)malloc(sizeof(int64_t) * (*n_bonds));
     if(!*to_atoms)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-               sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         free(*from_atoms);
         *from_atoms = 0;
         return(TNG_CRITICAL);
@@ -8670,14 +8617,13 @@ tng_function_status DECLSPECDLLEXPORT tng_particle_mapping_add
 
     frame_set->n_mapping_blocks++;
 
-    mapping = realloc(frame_set->mappings, sizeof(struct tng_particle_mapping) *
-                      frame_set->n_mapping_blocks);
+    mapping = (tng_particle_mapping_t)realloc(frame_set->mappings, sizeof(struct tng_particle_mapping) *
+                                              frame_set->n_mapping_blocks);
 
     if(!mapping)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-               sizeof(struct tng_particle_mapping)*frame_set->n_mapping_blocks,
-               __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         free(frame_set->mappings);
         frame_set->mappings = 0;
         return(TNG_CRITICAL);
@@ -8687,11 +8633,11 @@ tng_function_status DECLSPECDLLEXPORT tng_particle_mapping_add
     frame_set->mappings[frame_set->n_mapping_blocks - 1].num_first_particle = num_first_particle;
     frame_set->mappings[frame_set->n_mapping_blocks - 1].n_particles = n_particles;
 
-    frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers = malloc(sizeof(int64_t) * n_particles);
+    frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers = (int64_t *)malloc(sizeof(int64_t) * n_particles);
     if(!frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-               sizeof(int64_t) * n_particles, __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         return(TNG_CRITICAL);
     }
 
@@ -8738,11 +8684,11 @@ tng_function_status DECLSPECDLLEXPORT tng_trajectory_init(tng_trajectory_t *tng_
     tng_trajectory_frame_set_t frame_set;
     tng_trajectory_t tng_data;
 
-    *tng_data_p = malloc(sizeof(struct tng_trajectory));
+    *tng_data_p = (tng_trajectory_t)malloc(sizeof(struct tng_trajectory));
     if(!*tng_data_p)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIuPTR" bytes). %s: %d\n",
-               sizeof(struct tng_trajectory), __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         return(TNG_CRITICAL);
     }
 
@@ -9262,11 +9208,11 @@ tng_function_status DECLSPECDLLEXPORT tng_trajectory_init_from_src
 
     TNG_ASSERT(src != 0, "TNG library: Source trajectory must not be NULL.");
 
-    *dest_p = malloc(sizeof(struct tng_trajectory));
+    *dest_p = (tng_trajectory_t)malloc(sizeof(struct tng_trajectory));
     if(!*dest_p)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIuPTR" bytes). %s: %d\n",
-               sizeof(struct tng_trajectory), __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         return(TNG_CRITICAL);
     }
 
@@ -9276,11 +9222,11 @@ tng_function_status DECLSPECDLLEXPORT tng_trajectory_init_from_src
 
     if(src->input_file_path)
     {
-        dest->input_file_path = malloc(strlen(src->input_file_path) + 1);
+        dest->input_file_path = (char *)malloc(strlen(src->input_file_path) + 1);
         if(!dest->input_file_path)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n",
-                   (unsigned int)strlen(src->input_file_path) + 1, __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
         strcpy(dest->input_file_path, src->input_file_path);
@@ -9293,11 +9239,11 @@ tng_function_status DECLSPECDLLEXPORT tng_trajectory_init_from_src
     dest->input_file = 0;
     if(src->output_file_path)
     {
-        dest->output_file_path = malloc(strlen(src->output_file_path) + 1);
+        dest->output_file_path = (char *)malloc(strlen(src->output_file_path) + 1);
         if(!dest->output_file_path)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n",
-                   (unsigned int)strlen(src->output_file_path) + 1, __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
         strcpy(dest->output_file_path, src->output_file_path);
@@ -9431,11 +9377,11 @@ tng_function_status DECLSPECDLLEXPORT tng_input_file_set
     }
 
     len = tng_min_size(strlen(file_name) + 1, TNG_MAX_STR_LEN);
-    temp = realloc(tng_data->input_file_path, len);
+    temp = (char *)realloc(tng_data->input_file_path, len);
     if(!temp)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
-               __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         free(tng_data->input_file_path);
         tng_data->input_file_path = 0;
         return(TNG_CRITICAL);
@@ -9487,11 +9433,11 @@ tng_function_status DECLSPECDLLEXPORT tng_output_file_set
     }
 
     len = tng_min_size(strlen(file_name) + 1, TNG_MAX_STR_LEN);
-    temp = realloc(tng_data->output_file_path, len);
+    temp = (char *)realloc(tng_data->output_file_path, len);
     if(!temp)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
-               __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         free(tng_data->output_file_path);
         tng_data->output_file_path = 0;
         return(TNG_CRITICAL);
@@ -9525,11 +9471,11 @@ tng_function_status DECLSPECDLLEXPORT tng_output_append_file_set
     }
 
     len = tng_min_size(strlen(file_name) + 1, TNG_MAX_STR_LEN);
-    temp = realloc(tng_data->output_file_path, len);
+    temp = (char *)realloc(tng_data->output_file_path, len);
     if(!temp)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
-               __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         free(tng_data->output_file_path);
         tng_data->output_file_path = 0;
         return(TNG_CRITICAL);
@@ -9726,11 +9672,11 @@ tng_function_status DECLSPECDLLEXPORT tng_first_program_name_set
     }
     if(!tng_data->first_program_name)
     {
-        tng_data->first_program_name = malloc(len);
+        tng_data->first_program_name = (char *)malloc(len);
         if(!tng_data->first_program_name)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
-                   __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
     }
@@ -9775,11 +9721,11 @@ tng_function_status DECLSPECDLLEXPORT tng_last_program_name_set
     }
     if(!tng_data->last_program_name)
     {
-        tng_data->last_program_name = malloc(len);
+        tng_data->last_program_name = (char *)malloc(len);
         if(!tng_data->last_program_name)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
-                   __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
     }
@@ -9826,11 +9772,11 @@ tng_function_status DECLSPECDLLEXPORT tng_first_user_name_set
     }
     if(!tng_data->first_user_name)
     {
-        tng_data->first_user_name = malloc(len);
+        tng_data->first_user_name = (char *)malloc(len);
         if(!tng_data->first_user_name)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
-                   __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
     }
@@ -9877,11 +9823,11 @@ tng_function_status DECLSPECDLLEXPORT tng_last_user_name_set
     }
     if(!tng_data->last_user_name)
     {
-        tng_data->last_user_name = malloc(len);
+        tng_data->last_user_name = (char *)malloc(len);
         if(!tng_data->last_user_name)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
-                   __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
     }
@@ -9928,11 +9874,11 @@ tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_set
     }
     if(!tng_data->first_computer_name)
     {
-        tng_data->first_computer_name = malloc(len);
+        tng_data->first_computer_name = (char *)malloc(len);
         if(!tng_data->first_computer_name)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
-                   __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
     }
@@ -9980,11 +9926,11 @@ tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_set
     }
     if(!tng_data->last_computer_name)
     {
-        tng_data->last_computer_name = malloc(len);
+        tng_data->last_computer_name = (char *)malloc(len);
         if(!tng_data->last_computer_name)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
-                   __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
     }
@@ -10032,11 +9978,11 @@ tng_function_status DECLSPECDLLEXPORT tng_first_signature_set
     }
     if(!tng_data->first_pgp_signature)
     {
-        tng_data->first_pgp_signature = malloc(len);
+        tng_data->first_pgp_signature = (char *)malloc(len);
         if(!tng_data->first_pgp_signature)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
-                   __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
     }
@@ -10084,11 +10030,11 @@ tng_function_status DECLSPECDLLEXPORT tng_last_signature_set
     }
     if(!tng_data->last_pgp_signature)
     {
-        tng_data->last_pgp_signature = malloc(len);
+        tng_data->last_pgp_signature = (char *)malloc(len);
         if(!tng_data->last_pgp_signature)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
-                   __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
     }
@@ -10135,11 +10081,11 @@ tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_set
     }
     if(!tng_data->forcefield_name)
     {
-        tng_data->forcefield_name = malloc(len);
+        tng_data->forcefield_name = (char *)malloc(len);
         if(!tng_data->forcefield_name)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
-                   __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
     }
@@ -10283,7 +10229,7 @@ tng_function_status DECLSPECDLLEXPORT tng_num_frames_get
     stat = tng_block_header_read(tng_data, block);
     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
     {
-        fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", last_file_pos,
+        fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", last_file_pos,
                 __FILE__, __LINE__);
         tng_block_destroy(&block);
         return(TNG_FAILURE);
@@ -10605,7 +10551,7 @@ tng_function_status DECLSPECDLLEXPORT tng_num_frame_sets_get
     stat = tng_block_header_read(tng_data, block);
     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
     {
-        fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", file_pos,
+        fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", file_pos,
                 __FILE__, __LINE__);
         tng_block_destroy(&block);
         return(TNG_CRITICAL);
@@ -10636,7 +10582,7 @@ tng_function_status DECLSPECDLLEXPORT tng_num_frame_sets_get
             stat = tng_block_header_read(tng_data, block);
             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
             {
-                fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+                fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                        file_pos, __FILE__, __LINE__);
                 tng_block_destroy(&block);
                 return(TNG_CRITICAL);
@@ -10667,7 +10613,7 @@ tng_function_status DECLSPECDLLEXPORT tng_num_frame_sets_get
             stat = tng_block_header_read(tng_data, block);
             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
             {
-                fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+                fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                        file_pos, __FILE__, __LINE__);
                 tng_block_destroy(&block);
                 return(TNG_CRITICAL);
@@ -10697,7 +10643,7 @@ tng_function_status DECLSPECDLLEXPORT tng_num_frame_sets_get
             stat = tng_block_header_read(tng_data, block);
             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
             {
-                fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+                fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                        file_pos, __FILE__, __LINE__);
                 tng_block_destroy(&block);
                 return(TNG_CRITICAL);
@@ -10800,7 +10746,7 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find
     stat = tng_block_header_read(tng_data, block);
     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
     {
-        fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", file_pos,
+        fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", file_pos,
                 __FILE__, __LINE__);
         tng_block_destroy(&block);
         return(TNG_CRITICAL);
@@ -10834,7 +10780,7 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find
             stat = tng_block_header_read(tng_data, block);
             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
             {
-                fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+                fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                        file_pos,  __FILE__, __LINE__);
                 tng_block_destroy(&block);
                 return(TNG_CRITICAL);
@@ -10869,7 +10815,7 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find
             stat = tng_block_header_read(tng_data, block);
             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
             {
-                fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+                fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                        file_pos, __FILE__, __LINE__);
                 tng_block_destroy(&block);
                 return(TNG_CRITICAL);
@@ -10904,7 +10850,7 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find
             stat = tng_block_header_read(tng_data, block);
             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
             {
-                fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+                fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                        file_pos, __FILE__, __LINE__);
                 tng_block_destroy(&block);
                 return(TNG_CRITICAL);
@@ -10939,7 +10885,7 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find
             stat = tng_block_header_read(tng_data, block);
             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
             {
-                fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+                fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                        file_pos, __FILE__, __LINE__);
                 tng_block_destroy(&block);
                 return(TNG_CRITICAL);
@@ -10974,7 +10920,7 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find
             stat = tng_block_header_read(tng_data, block);
             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
             {
-                fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+                fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                        file_pos, __FILE__, __LINE__);
                 tng_block_destroy(&block);
                 return(TNG_CRITICAL);
@@ -11008,7 +10954,7 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find
             stat = tng_block_header_read(tng_data, block);
             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
             {
-                fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+                fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                        file_pos, __FILE__, __LINE__);
                 tng_block_destroy(&block);
                 return(TNG_CRITICAL);
@@ -11043,7 +10989,7 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find
             stat = tng_block_header_read(tng_data, block);
             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
             {
-                fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+                fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                        file_pos, __FILE__, __LINE__);
                 tng_block_destroy(&block);
                 return(TNG_CRITICAL);
@@ -11096,7 +11042,7 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find
         stat = tng_block_header_read(tng_data, block);
         if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
         {
-            fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+            fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                     file_pos, __FILE__, __LINE__);
             tng_block_destroy(&block);
             return(TNG_CRITICAL);
@@ -11179,7 +11125,7 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find
             stat = tng_block_header_read(tng_data, block);
             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
             {
-                fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+                fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                        file_pos, __FILE__, __LINE__);
                 tng_block_destroy(&block);
                 return(TNG_CRITICAL);
@@ -11218,7 +11164,7 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find
             stat = tng_block_header_read(tng_data, block);
             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
             {
-                fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+                fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                        file_pos, __FILE__, __LINE__);
                 tng_block_destroy(&block);
                 return(TNG_CRITICAL);
@@ -11255,7 +11201,7 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find
             stat = tng_block_header_read(tng_data, block);
             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
             {
-                fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+                fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                        file_pos, __FILE__, __LINE__);
                 tng_block_destroy(&block);
                 return(TNG_CRITICAL);
@@ -11290,7 +11236,7 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find
             stat = tng_block_header_read(tng_data, block);
             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
             {
-                fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+                fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                        file_pos, __FILE__, __LINE__);
                 tng_block_destroy(&block);
                 return(TNG_CRITICAL);
@@ -11327,7 +11273,7 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find
             stat = tng_block_header_read(tng_data, block);
             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
             {
-                fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+                fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                        file_pos, __FILE__, __LINE__);
                 tng_block_destroy(&block);
                 return(TNG_CRITICAL);
@@ -11364,7 +11310,7 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find
             stat = tng_block_header_read(tng_data, block);
             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
             {
-                fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+                fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                        file_pos, __FILE__, __LINE__);
                 tng_block_destroy(&block);
                 return(TNG_CRITICAL);
@@ -11399,7 +11345,7 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find
             stat = tng_block_header_read(tng_data, block);
             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
             {
-                fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+                fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                        file_pos, __FILE__, __LINE__);
                 tng_block_destroy(&block);
                 return(TNG_CRITICAL);
@@ -11435,7 +11381,7 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find
             stat = tng_block_header_read(tng_data, block);
             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
             {
-                fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+                fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                        file_pos, __FILE__, __LINE__);
                 tng_block_destroy(&block);
                 return(TNG_CRITICAL);
@@ -11688,11 +11634,11 @@ tng_function_status DECLSPECDLLEXPORT tng_file_headers_write
         }
 
         tng_block_init(&block);
-        block->name = malloc(TNG_MAX_STR_LEN);
+        block->name = (char *)malloc(TNG_MAX_STR_LEN);
         if(!block->name)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
-                    TNG_MAX_STR_LEN, __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             tng_block_destroy(&block);
             return(TNG_CRITICAL);
         }
@@ -11737,6 +11683,7 @@ tng_function_status DECLSPECDLLEXPORT tng_file_headers_write
         if(tot_len > orig_len)
         {
             tng_migrate_data_in_file(tng_data, orig_len+1, tot_len - orig_len, hash_mode);
+            tng_data->last_trajectory_frame_set_input_file_pos = tng_data->last_trajectory_frame_set_output_file_pos;
         }
 
         stat = tng_reread_frame_set_at_file_pos(tng_data, tng_data->last_trajectory_frame_set_input_file_pos);
@@ -11854,7 +11801,7 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_read
     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET ||
        block->id == -1)
     {
-        fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+        fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                file_pos, __FILE__, __LINE__);
         tng_block_destroy(&block);
         return(TNG_CRITICAL);
@@ -11887,7 +11834,7 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_read
         }
         if(stat == TNG_CRITICAL)
         {
-            fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+            fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                    file_pos, __FILE__, __LINE__);
             tng_block_destroy(&block);
             return(stat);
@@ -11949,7 +11896,7 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_current_only_data_from_
     stat = tng_block_header_read(tng_data, block);
     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
     {
-        fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+        fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                file_pos, __FILE__, __LINE__);
         tng_block_destroy(&block);
         return(TNG_CRITICAL);
@@ -12009,7 +11956,7 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_current_only_data_from_
     }
     if(stat == TNG_CRITICAL)
     {
-        fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+        fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                 file_pos, __FILE__, __LINE__);
         tng_block_destroy(&block);
         return(stat);
@@ -12106,7 +12053,7 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next_only_data_from_blo
     stat = tng_block_header_read(tng_data, block);
     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
     {
-        fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+        fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                 file_pos, __FILE__, __LINE__);
         tng_block_destroy(&block);
         return(TNG_CRITICAL);
@@ -12326,7 +12273,7 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_new
             if(tng_data->input_endianness_swap_func_64)
             {
                 if(tng_data->input_endianness_swap_func_64(tng_data,
-                   &frame_set->medium_stride_prev_frame_set_file_pos)
+                   (uint64_t *)&frame_set->medium_stride_prev_frame_set_file_pos)
                     != TNG_SUCCESS)
                 {
                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
@@ -12384,7 +12331,7 @@ tng_function_status DECLSPECDLLEXPORT tng_frame_set_new
                     if(tng_data->input_endianness_swap_func_64)
                     {
                         if(tng_data->input_endianness_swap_func_64(tng_data,
-                           &frame_set->long_stride_prev_frame_set_file_pos)
+                           (uint64_t *)&frame_set->long_stride_prev_frame_set_file_pos)
                             != TNG_SUCCESS)
                         {
                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
@@ -12499,7 +12446,7 @@ tng_function_status DECLSPECDLLEXPORT tng_first_frame_nr_of_next_frame_set_get
     stat = tng_block_header_read(tng_data, block);
     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
     {
-        fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+        fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                file_pos, __FILE__, __LINE__);
         return(TNG_CRITICAL);
     }
@@ -12541,7 +12488,7 @@ static tng_function_status tng_gen_data_block_add
     char ***first_dim_values, **second_dim_values;
     tng_trajectory_frame_set_t frame_set;
     tng_data_t data;
-    char *new_data_c=new_data;
+    char *new_data_c = (char *)new_data;
     tng_function_status stat;
 
     frame_set = &tng_data->current_trajectory_frame_set;
@@ -12603,11 +12550,11 @@ static tng_function_status tng_gen_data_block_add
         }
         data->block_id = id;
 
-        data->block_name = malloc(strlen(block_name) + 1);
+        data->block_name = (char *)malloc(strlen(block_name) + 1);
         if(!data->block_name)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n",
-                   (unsigned int)strlen(block_name)+1, __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             return(TNG_CRITICAL);
         }
         strncpy(data->block_name, block_name, strlen(block_name) + 1);
@@ -12710,11 +12657,11 @@ static tng_function_status tng_gen_data_block_add
                             {
                                 free(second_dim_values[k]);
                             }
-                            second_dim_values[k] = malloc(len);
+                            second_dim_values[k] = (char *)malloc(len);
                             if(!second_dim_values[k])
                             {
-                                fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
-                                    len, __FILE__, __LINE__);
+                                fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                                        __FILE__, __LINE__);
                                 return(TNG_CRITICAL);
                             }
                             strncpy(second_dim_values[k],
@@ -12737,11 +12684,11 @@ static tng_function_status tng_gen_data_block_add
                         {
                             free(second_dim_values[j]);
                         }
-                        second_dim_values[j] = malloc(len);
+                        second_dim_values[j] = (char *)malloc(len);
                         if(!second_dim_values[j])
                         {
-                            fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
-                                len, __FILE__, __LINE__);
+                            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                                    __FILE__, __LINE__);
                             return(TNG_CRITICAL);
                         }
                         strncpy(second_dim_values[j],
@@ -13285,7 +13232,7 @@ static tng_function_status tng_frame_gen_data_write
     stat = tng_block_header_read(tng_data, block);
     if(stat == TNG_CRITICAL)
     {
-        fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+        fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                file_pos, __FILE__, __LINE__);
         tng_block_destroy(&block);
         tng_data->input_file = temp;
@@ -13348,7 +13295,7 @@ static tng_function_status tng_frame_gen_data_write
             }
             if(stat == TNG_CRITICAL)
             {
-                fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+                fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                        file_pos, __FILE__, __LINE__);
                 tng_block_destroy(&block);
                 tng_data->input_file = temp;
@@ -13391,7 +13338,7 @@ static tng_function_status tng_frame_gen_data_write
     }
     if(stat == TNG_CRITICAL)
     {
-        fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+        fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                file_pos, __FILE__, __LINE__);
         tng_block_destroy(&block);
         tng_data->input_file = temp;
@@ -13581,12 +13528,12 @@ static tng_function_status tng_frame_gen_data_write
         data.datatype == TNG_DOUBLE_DATA) &&
        tng_data->output_endianness_swap_func_64)
     {
-        copy = malloc(write_n_particles * n_values_per_frame * size);
+        copy = (char *)malloc(write_n_particles * n_values_per_frame * size);
         memcpy(copy, values, write_n_particles * n_values_per_frame * size);
         for(i = 0; i < write_n_particles * n_values_per_frame; i++)
         {
             if(tng_data->output_endianness_swap_func_64(tng_data,
-                (int64_t *) copy+i)
+                (uint64_t *) copy+i)
                 != TNG_SUCCESS)
             {
                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
@@ -13600,12 +13547,12 @@ static tng_function_status tng_frame_gen_data_write
     else if(data.datatype == TNG_FLOAT_DATA &&
             tng_data->output_endianness_swap_func_32)
     {
-        copy = malloc(write_n_particles * n_values_per_frame * size);
+        copy = (char *)malloc(write_n_particles * n_values_per_frame * size);
         memcpy(copy, values, write_n_particles * n_values_per_frame * size);
         for(i = 0; i < write_n_particles * n_values_per_frame; i++)
         {
             if(tng_data->output_endianness_swap_func_32(tng_data,
-                (int32_t *) copy+i)
+                (uint32_t *) copy+i)
                 != TNG_SUCCESS)
             {
                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
@@ -13712,25 +13659,23 @@ static tng_function_status tng_data_values_alloc
             return(stat);
         }
     }
-    *values = malloc(sizeof(union data_values *) * n_frames);
+    *values = (union data_values **)malloc(sizeof(union data_values *) * n_frames);
     if(!*values)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-               sizeof(union data_values **) * n_frames,
-               __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         return(TNG_CRITICAL);
 
     }
 
     for(i = 0; i < n_frames; i++)
     {
-        (*values)[i] = malloc(sizeof(union data_values) *
+        (*values)[i] = (union data_values *)malloc(sizeof(union data_values) *
                            n_values_per_frame);
         if(!(*values)[i])
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-                   sizeof(union data_values) * n_values_per_frame,
-                   __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             free(values);
             values = 0;
             return(TNG_CRITICAL);
@@ -13806,38 +13751,35 @@ static tng_function_status tng_particle_data_values_alloc
             return(stat);
         }
     }
-    *values = malloc(sizeof(union data_values **) * n_frames);
+    *values = (union data_values ***)malloc(sizeof(union data_values **) * n_frames);
     if(!*values)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-               sizeof(union data_values **) * n_frames,
-               __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         return(TNG_CRITICAL);
 
     }
 
     for(i = 0; i < n_frames; i++)
     {
-        (*values)[i] = malloc(sizeof(union data_values *) *
+        (*values)[i] = (union data_values **)malloc(sizeof(union data_values *) *
                            n_particles);
         if(!(*values)[i])
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-                   sizeof(union data_values *) * n_particles,
-                   __FILE__, __LINE__);
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                    __FILE__, __LINE__);
             free(*values);
             *values = 0;
             return(TNG_CRITICAL);
         }
         for(j = 0; j < n_particles; j++)
         {
-            (*values)[i][j] = malloc(sizeof(union data_values) *
+            (*values)[i][j] = (union data_values *)malloc(sizeof(union data_values) *
                                   n_values_per_frame);
             if(!(*values)[i][j])
             {
-                fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-                    sizeof(union data_values *) * n_particles,
-                    __FILE__, __LINE__);
+                fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                        __FILE__, __LINE__);
                 tng_particle_data_values_free(tng_data, *values, n_frames,
                                               n_particles, n_values_per_frame,
                                               type);
@@ -13962,7 +13904,7 @@ static tng_function_status tng_gen_data_get
         tng_block_destroy(&block);
         if(stat == TNG_CRITICAL)
         {
-            fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+            fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                     file_pos, __FILE__, __LINE__);
             return(stat);
         }
@@ -14043,7 +13985,7 @@ static tng_function_status tng_gen_data_get
                     for(k = 0; k < *n_values_per_frame; k++)
                     {
                         len = strlen(data->strings[i][j][k]) + 1;
-                        (*values)[i][mapping][k].c = malloc(len);
+                        (*values)[i][mapping][k].c = (char *)malloc(len);
                         strncpy((*values)[i][mapping][k].c,
                                 data->strings[i][j][k], len);
                     }
@@ -14122,7 +14064,7 @@ static tng_function_status tng_gen_data_get
                 for(j = 0; j < *n_values_per_frame; j++)
                 {
                     len = strlen(data->strings[0][i][j]) + 1;
-                    (*values)[0][i][j].c = malloc(len);
+                    (*values)[0][i][j].c = (char *)malloc(len);
                     strncpy((*values)[0][i][j].c, data->strings[0][i][j], len);
                 }
             }
@@ -14246,7 +14188,7 @@ static tng_function_status tng_gen_data_vector_get
         tng_block_destroy(&block);
         if(stat == TNG_CRITICAL)
         {
-            fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+            fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                     file_pos, __FILE__, __LINE__);
             return(stat);
         }
@@ -14320,11 +14262,11 @@ static tng_function_status tng_gen_data_vector_get
         full_data_len *= (*n_particles);
     }
 
-    temp = realloc(*values, full_data_len);
+    temp = (char *)realloc(*values, full_data_len);
     if(!temp)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
-               full_data_len, __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         free(*values);
         *values = 0;
         return(TNG_CRITICAL);
@@ -14442,7 +14384,7 @@ static tng_function_status tng_gen_data_interval_get
         tng_block_destroy(&block);
         if(stat == TNG_CRITICAL)
         {
-            fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+            fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                     file_pos, __FILE__, __LINE__);
             return(stat);
         }
@@ -14478,7 +14420,7 @@ static tng_function_status tng_gen_data_interval_get
 
     if(block_index < 0)
     {
-        fprintf(stderr, "TNG library: Could not find particle data block with id %"PRId64". %s: %d\n",
+        fprintf(stderr, "TNG library: Could not find particle data block with id %" PRId64 ". %s: %d\n",
                 block_id, __FILE__, __LINE__);
         return(TNG_FAILURE);
     }
@@ -14557,7 +14499,7 @@ static tng_function_status tng_gen_data_interval_get
                     for(k = 0; k < *n_values_per_frame; k++)
                     {
                         len = strlen(data->strings[current_frame_pos][j][k]) + 1;
-                        (*values)[i][mapping][k].c = malloc(len);
+                        (*values)[i][mapping][k].c = (char *)malloc(len);
                         strncpy((*values)[i][mapping][k].c, data->strings[current_frame_pos][j][k], len);
                     }
                 }
@@ -14567,7 +14509,7 @@ static tng_function_status tng_gen_data_interval_get
                 for(j = 0; j < *n_values_per_frame; j++)
                 {
                     len = strlen(data->strings[0][current_frame_pos][j]) + 1;
-                    (*values)[0][i][j].c = malloc(len);
+                    (*values)[0][i][j].c = (char *)malloc(len);
                     strncpy((*values)[0][i][j].c, data->strings[0][current_frame_pos][j], len);
                 }
             }
@@ -14816,7 +14758,7 @@ static tng_function_status tng_gen_data_vector_interval_get
         tng_block_destroy(&block);
         if(stat == TNG_CRITICAL)
         {
-            fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+            fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                     file_pos, __FILE__, __LINE__);
             return(stat);
         }
@@ -14881,11 +14823,11 @@ static tng_function_status tng_gen_data_vector_interval_get
         full_data_len *= (*n_particles);
     }
 
-    temp = realloc(*values, full_data_len);
+    temp = (char *)realloc(*values, full_data_len);
     if(!temp)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
-               full_data_len, __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         free(*values);
         *values = 0;
         return(TNG_CRITICAL);
@@ -15285,6 +15227,9 @@ tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_open
         tng_output_append_file_set(*tng_data_p, filename);
 
         fseeko((*tng_data_p)->output_file, 0, SEEK_END);
+
+        (*tng_data_p)->output_endianness_swap_func_32 = (*tng_data_p)->input_endianness_swap_func_32;
+        (*tng_data_p)->output_endianness_swap_func_64 = (*tng_data_p)->input_endianness_swap_func_64;
     }
 
     return(stat);
@@ -15333,7 +15278,7 @@ tng_function_status DECLSPECDLLEXPORT tng_util_time_of_frame_get
     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
     if(stat != TNG_SUCCESS)
     {
-        fprintf(stderr, "TNG library: Cannot find frame nr %"PRId64". %s: %d\n",
+        fprintf(stderr, "TNG library: Cannot find frame nr %" PRId64 ". %s: %d\n",
                frame_nr, __FILE__, __LINE__);
         return(stat);
     }
@@ -15421,25 +15366,25 @@ tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_get
 
     *n_particles = mol->n_atoms;
 
-    *names = malloc(sizeof(char *) * *n_particles);
-    *types = malloc(sizeof(char *) * *n_particles);
-    *res_names = malloc(sizeof(char *) * *n_particles);
-    *chain_names = malloc(sizeof(char *) * *n_particles);
-    *res_ids = malloc(sizeof(int64_t) * *n_particles);
-    *chain_ids = malloc(sizeof(int64_t) * *n_particles);
+    *names = (char **)malloc(sizeof(char *) * *n_particles);
+    *types = (char **)malloc(sizeof(char *) * *n_particles);
+    *res_names = (char **)malloc(sizeof(char *) * *n_particles);
+    *chain_names = (char **)malloc(sizeof(char *) * *n_particles);
+    *res_ids = (int64_t *)malloc(sizeof(int64_t) * *n_particles);
+    *chain_ids = (int64_t *)malloc(sizeof(int64_t) * *n_particles);
 
     for(i = 0; i < *n_particles; i++)
     {
         atom = &mol->atoms[i];
         res = atom->residue;
         chain = res->chain;
-        (*names)[i] = malloc(strlen(atom->name));
+        (*names)[i] = (char *)malloc(strlen(atom->name));
         strcpy(*names[i], atom->name);
-        (*types)[i] = malloc(strlen(atom->atom_type));
+        (*types)[i] = (char *)malloc(strlen(atom->atom_type));
         strcpy(*types[i], atom->atom_type);
-        (*res_names)[i] = malloc(strlen(res->name));
+        (*res_names)[i] = (char *)malloc(strlen(res->name));
         strcpy(*res_names[i], res->name);
-        (*chain_names)[i] = malloc(strlen(chain->name));
+        (*chain_names)[i] = (char *)malloc(strlen(chain->name));
         strcpy(*chain_names[i], chain->name);
         (*res_ids)[i] = res->id;
         (*chain_ids)[i] = chain->id;
@@ -15530,6 +15475,11 @@ tng_function_status DECLSPECDLLEXPORT tng_util_pos_read
                                                  &n_values_per_frame,
                                                  &type);
 
+    if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
+    {
+        return(TNG_FAILURE);
+    }
+
     return(stat);
 }
 
@@ -15559,6 +15509,11 @@ tng_function_status DECLSPECDLLEXPORT tng_util_vel_read
                                                  &n_values_per_frame,
                                                  &type);
 
+    if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
+    {
+        return(TNG_FAILURE);
+    }
+
     return(stat);
 }
 
@@ -15588,6 +15543,11 @@ tng_function_status DECLSPECDLLEXPORT tng_util_force_read
                                                  &n_values_per_frame,
                                                  &type);
 
+    if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
+    {
+        return(TNG_FAILURE);
+    }
+
     return(stat);
 }
 
@@ -15617,6 +15577,11 @@ tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read
                                         &n_values_per_frame,
                                         &type);
 
+    if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
+    {
+        return(TNG_FAILURE);
+    }
+
     return(stat);
 }
 
@@ -15764,14 +15729,14 @@ tng_function_status DECLSPECDLLEXPORT tng_util_particle_data_next_frame_read
 
     full_data_len = size * n_particles * data->n_values_per_frame;
 
-//     fprintf(stderr, "TNG library: TEMP: i = %"PRId64", full_data_len = %"PRId64", size = %d, n_particles = %"PRId64", n_values_per_frame = %"PRId64"\n",
+//     fprintf(stderr, "TNG library: TEMP: i = %" PRId64 ", full_data_len = %" PRId64 ", size = %d, n_particles = %" PRId64 ", n_values_per_frame = %" PRId64 "\n",
 //            i, full_data_len, size, n_particles, data->n_values_per_frame);
 
-    temp = realloc(*values, full_data_len);
+    temp = (char *)realloc(*values, full_data_len);
     if(!temp)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
-               full_data_len, __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         free(*values);
         *values = 0;
         return(TNG_CRITICAL);
@@ -15926,11 +15891,11 @@ tng_function_status DECLSPECDLLEXPORT tng_util_non_particle_data_next_frame_read
 
     full_data_len = size * data->n_values_per_frame;
 
-    temp = realloc(*values, full_data_len);
+    temp = (char *)realloc(*values, full_data_len);
     if(!temp)
     {
-        fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
-               full_data_len, __FILE__, __LINE__);
+        fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                __FILE__, __LINE__);
         free(*values);
         *values = 0;
         return(TNG_CRITICAL);
@@ -16093,7 +16058,7 @@ tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_set
 
     if(i <= 0)
     {
-        fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
+        fprintf(stderr, "TNG library: Cannot set writing frequency to %" PRId64 ". %s: %d\n",
                i, __FILE__, __LINE__);
         return(TNG_FAILURE);
     }
@@ -16234,7 +16199,7 @@ tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_double_set
 
     if(i <= 0)
     {
-        fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
+        fprintf(stderr, "TNG library: Cannot set writing frequency to %" PRId64 ". %s: %d\n",
                i, __FILE__, __LINE__);
         return(TNG_FAILURE);
     }
@@ -17468,11 +17433,10 @@ tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_next_frame_present_dat
     {
         TNG_ASSERT(requested_data_block_ids, "TNG library: If the number of requested data blocks is > 0 then the array of data block IDs must not be NULL.");
         size = sizeof(int64_t) * n_requested_data_block_ids;
-        temp = realloc(*data_block_ids_in_next_frame, size);
+        temp = (int64_t *)realloc(*data_block_ids_in_next_frame, size);
         if(!temp)
         {
-            fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-                    sizeof(int64_t) * (*n_data_blocks_in_next_frame),
+            fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
                     __FILE__, __LINE__);
             free(*data_block_ids_in_next_frame);
             *data_block_ids_in_next_frame = 0;
@@ -17532,7 +17496,7 @@ tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_next_frame_present_dat
             tng_block_destroy(&block);
             if(stat == TNG_CRITICAL)
             {
-                fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+                fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
                         file_pos, __FILE__, __LINE__);
                 return(stat);
             }
@@ -17610,12 +17574,11 @@ tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_next_frame_present_dat
             if(n_requested_data_block_ids <= 0)
             {
                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
-                temp = realloc(*data_block_ids_in_next_frame, size);
+                temp = (int64_t *)realloc(*data_block_ids_in_next_frame, size);
                 if(!temp)
                 {
-                    fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-                           sizeof(int64_t) * (*n_data_blocks_in_next_frame),
-                           __FILE__, __LINE__);
+                    fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                            __FILE__, __LINE__);
                     free(*data_block_ids_in_next_frame);
                     *data_block_ids_in_next_frame = 0;
                     return(TNG_CRITICAL);
@@ -17697,12 +17660,11 @@ tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_next_frame_present_dat
             if(n_requested_data_block_ids <= 0)
             {
                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
-                temp = realloc(*data_block_ids_in_next_frame, size);
+                temp = (int64_t *)realloc(*data_block_ids_in_next_frame, size);
                 if(!temp)
                 {
-                    fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
-                           sizeof(int64_t) * (*n_data_blocks_in_next_frame),
-                           __FILE__, __LINE__);
+                    fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+                            __FILE__, __LINE__);
                     free(*data_block_ids_in_next_frame);
                     *data_block_ids_in_next_frame = 0;
                     return(TNG_CRITICAL);
index d53d15b07b043b8cfddb753003e22f75a1edaeca..70a6232a835846defb5e5055e889ba0ce3d811f4 100644 (file)
@@ -9,7 +9,7 @@
  * modify it under the terms of the Revised BSD License.
  */
 
-#include "../../include/tng_io.h"
+#include "tng/tng_io.h"
 
 /* The following is for calling the library from fortran */
 
index f465b6b7c00b607d8a2b226660f72e6e9328ab5a..480c6a390dd6f0056dc798cd2d21a76e7a82bf5d 100644 (file)
@@ -2,8 +2,6 @@ if(TNG_BUILD_COMPRESSION_TESTS)
   add_subdirectory(compression)
 endif()
 
-link_directories(${TNG_IO_BINARY_DIR}/src/lib)
-
 add_definitions(-DTNG_EXAMPLE_FILES_DIR="${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/tests/example_files/") # Directory where to find input test files and save output files.
 
 if(TNG_BUILD_TEST)
@@ -80,7 +78,7 @@ if(TNG_BUILD_EXAMPLES)
         if(${CMAKE_Fortran_COMPILER_WORKS})
             get_filename_component (Fortran_COMPILER_NAME ${CMAKE_Fortran_COMPILER} NAME)
             if (Fortran_COMPILER_NAME STREQUAL "gfortran")
-                set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -fcray-pointer ${OpenMP_C_FLAGS} -std=legacy")
+                set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -fcray-pointer ${OpenMP_C_FLAGS} -std=legacy -cpp -ffixed-line-length-none")
             endif()
             if(OPENMP_FOUND)
                 add_executable(md_openmp_f md_openmp.f)
index 87b00b8597644ec35ad71c7e4ebc3254905b8fc7..6399ae25d4e7a311899ded67484e5abc2eb771fa 100644 (file)
@@ -10,7 +10,7 @@ c    The program implements a simple molecular dynamics simulation.
 c
 c    The program uses Open MP directives to allow parallel computation.
 c
-c    The velocity Verlet time integration scheme is used. 
+c    The velocity Verlet time integration scheme is used.
 c
 c    The particles interact with a central pair potential.
 c
@@ -19,7 +19,7 @@ c    code is included in the TNG API release.
 c
 c  Licensing:
 c
-c    This code is distributed under the GNU LGPL license. 
+c    This code is distributed under the GNU LGPL license.
 c
 c  Modified:
 c
@@ -142,26 +142,26 @@ c
       write ( *, '(a)' ) ' '
       write ( *, '(a)' ) '  A molecular dynamics program.'
       write ( *, '(a)' ) ' '
-      write ( *, '(a,i8)' ) 
+      write ( *, '(a,i8)' )
      &  '  NP, the number of particles in the simulation is ', np
-      write ( *, '(a,i8)' ) 
+      write ( *, '(a,i8)' )
      &  '  STEP_NUM, the number of time steps, is ', step_num
-      write ( *, '(a,g14.6)' ) 
+      write ( *, '(a,g14.6)' )
      &  '  DT, the size of each time step, is ', dt
       write ( *, '(a)' ) ' '
-      write ( *, '(a,i8)' ) 
+      write ( *, '(a,i8)' )
      &  '  The number of processors = ', omp_get_num_procs ( )
-      write ( *, '(a,i8)' ) 
+      write ( *, '(a,i8)' )
      &  '  The number of threads    = ', omp_get_max_threads ( )
 
-      write ( *, '(a)' ) ' '     
+      write ( *, '(a)' ) ' '
       write ( *, '(a)' ) '  Initializing trajectory storage.'
       call tng_trajectory_init(traj_p)
 
 c
 c  N.B. The TNG output file should be modified according to needs
-c      
-      call tng_output_file_set(traj, TNG_EXAMPLE_FILES_DIR "tng_md_out_f77.tng")
+c
+      call tng_output_file_set(traj, TNG_EXAMPLE_FILES_DIR"tng_md_out_f77.tng")
 
       write ( *, '(a)' ) '  Creating molecules in trajectory.'
       tng_n_particles = np
@@ -183,20 +183,20 @@ c
 
 c
 c  Add the box shape data block
-c     
+c
       call tng_data_block_add(traj, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
      &  TNG_DOUBLE_DATA, TNG_NON_TRAJECTORY_BLOCK, int(1, 8),
      &  int(9, 8), int(1, 8), TNG_UNCOMPRESSED, box_shape)
 
 c
 c  Write the file headers
-c    
+c
       call tng_file_headers_write(traj, TNG_USE_HASH)
-      
+
 c
 c  Set initial positions, velocities, and accelerations.
-c      
-      write ( *, '(a)' ) 
+c
+      write ( *, '(a)' )
      &  '  Initializing positions, velocities, and accelerations.'
       seed = 123456789
       call initialize ( np, nd, box, seed, pos, vel, acc )
@@ -206,7 +206,7 @@ c
       write ( *, '(a)' ) ' '
       write ( *, '(a)' ) '  Computing initial forces and energies.'
 
-      call compute ( np, nd, pos, vel, mass, force, potential, 
+      call compute ( np, nd, pos, vel, mass, force, potential,
      &  kinetic )
 
       e0 = potential + kinetic
@@ -215,7 +215,7 @@ c
 c  Saving frequency
 c
       step_save = 5
-      
+
       step_print = 0
       step_print_index = 0
       step_print_num = 10
@@ -230,29 +230,29 @@ c
      &  ' steps particle positions, velocities and forces are'
       write ( *, '(a)' ) '  saved to a TNG trajectory file.'
       write ( *, '(a)' )
-      write ( *, '(a)' ) 
+      write ( *, '(a)' )
      &  '  At each step, we report the potential and kinetic energies.'
-      write ( *, '(a)' ) 
+      write ( *, '(a)' )
      &  '  The sum of these energies should be a constant.'
-      write ( *, '(a)' ) 
+      write ( *, '(a)' )
      &  '  As an accuracy check, we also print the relative error'
       write ( *, '(a)' ) '  in the total energy.'
       write ( *, '(a)' ) ' '
-      write ( *, '(a)' ) 
+      write ( *, '(a)' )
      &  '      Step      Potential       Kinetic        (P+K-E0)/E0'
-      write ( *, '(a)' ) 
+      write ( *, '(a)' )
      &  '                Energy P        Energy K       ' //
      &  'Relative Energy Error'
       write ( *, '(a)' ) ' '
 
       step = 0
-      write ( *, '(2x,i8,2x,g14.6,2x,g14.6,2x,g14.6)' ) 
+      write ( *, '(2x,i8,2x,g14.6,2x,g14.6,2x,g14.6)' )
      &  step, potential, kinetic, ( potential + kinetic - e0 ) / e0
       step_print_index = step_print_index + 1
       step_print = ( step_print_index * step_num ) / step_print_num
 
-c      
-c  Create a frame set for writing data      
+c
+c  Create a frame set for writing data
 c
       call tng_num_frames_per_frame_set_get(traj,
      &  n_frames_per_frame_set)
@@ -265,12 +265,12 @@ c
      &  "POSITIONS", TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK,
      &  n_frames_per_frame_set, int(3, 8), int(1, 8), int(0, 8),
      &  tng_n_particles, TNG_UNCOMPRESSED, %VAL(int(0, 8)))
-      
+
       call tng_particle_data_block_add(traj, TNG_TRAJ_VELOCITIES,
      &  "VELOCITIES", TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK,
      &  n_frames_per_frame_set, int(3, 8), int(1, 8), int(0, 8),
      &  tng_n_particles, TNG_UNCOMPRESSED, %VAL(int(0, 8)))
-      
+
       call tng_particle_data_block_add(traj, TNG_TRAJ_FORCES,
      &  "FORCES", TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK,
      &  n_frames_per_frame_set, int(3, 8), int(1, 8), int(0, 8),
@@ -278,28 +278,28 @@ c
 
 c
 c  The potential energy data block is saved sparsely.
-c     
+c
       call tng_data_block_add(traj, int(10101, 8),
      &  "POTENTIAL ENERGY", TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK,
      &  n_frames_per_frame_set, int(1, 8), sparse_save,
      &  TNG_UNCOMPRESSED, %VAL(int(0, 8)))
-     
+
 
 c
 c  Write the frame set to disk
 c
       call tng_frame_set_write(traj, TNG_USE_HASH)
-      
+
       wtime = omp_get_wtime ( )
 
       do step = 1, step_num
 
-        call compute ( np, nd, pos, vel, mass, force, potential, 
+        call compute ( np, nd, pos, vel, mass, force, potential,
      &    kinetic )
 
         if ( step .eq. step_print ) then
 
-          write ( *, '(2x,i8,2x,g14.6,2x,g14.6,2x,g14.6)' ) 
+          write ( *, '(2x,i8,2x,g14.6,2x,g14.6,2x,g14.6)' )
      &      step, potential, kinetic, ( potential + kinetic - e0 ) / e0
 
           step_print_index = step_print_index + 1
@@ -321,12 +321,12 @@ c
      &    TNG_TRAJ_FORCES, int(0, 8), tng_n_particles, force,
      &    TNG_USE_HASH)
           frames_saved_cnt = frames_saved_cnt + 1
-          
+
           if (mod(step, step_save * sparse_save) .EQ. 0) then
             call tng_frame_data_write(traj, frames_saved_cnt,
      &      int(10101, 8), potential, TNG_USE_HASH)
           end if
-          
+
         end if
 
         call update ( np, nd, pos, vel, force, acc, mass, dt )
@@ -336,7 +336,7 @@ c
       wtime = omp_get_wtime ( ) - wtime
 
       write ( *, '(a)' ) ' '
-      write ( *, '(a)' ) 
+      write ( *, '(a)' )
      &  '  Elapsed time for main computation:'
       write ( *, '(2x,g14.6,a)' ) wtime, ' seconds'
 c
@@ -365,7 +365,7 @@ c    The computation of forces and energies is fully parallel.
 c
 c  Licensing:
 c
-c    This code is distributed under the GNU LGPL license. 
+c    This code is distributed under the GNU LGPL license.
 c
 c  Modified:
 c
@@ -413,9 +413,9 @@ c
       pot = 0.0D+00
       kin = 0.0D+00
 
-c$omp parallel 
-c$omp& shared ( f, nd, np, pos, vel ) 
-c$omp& private ( d, d2, i, j, k, rij ) 
+c$omp parallel
+c$omp& shared ( f, nd, np, pos, vel )
+c$omp& private ( d, d2, i, j, k, rij )
 
 c$omp do reduction ( + : pot, kin )
       do i = 1, np
@@ -458,7 +458,7 @@ c$omp end do
 c$omp end parallel
 
       kin = kin * 0.5D+00 * mass
-      
+
       return
       end
       subroutine dist ( nd, r1, r2, dr, d )
@@ -469,7 +469,7 @@ cc DIST computes the displacement (and its norm) between two particles.
 c
 c  Licensing:
 c
-c    This code is distributed under the GNU LGPL license. 
+c    This code is distributed under the GNU LGPL license.
 c
 c  Modified:
 c
@@ -520,7 +520,7 @@ cc INITIALIZE initializes the positions, velocities, and accelerations.
 c
 c  Licensing:
 c
-c    This code is distributed under the GNU LGPL license. 
+c    This code is distributed under the GNU LGPL license.
 c
 c  Modified:
 c
@@ -570,7 +570,7 @@ c
         end do
       end do
 
-c$omp parallel 
+c$omp parallel
 c$omp& shared ( acc, box, nd, np, pos, vel )
 c$omp& private ( i, j )
 
@@ -615,7 +615,7 @@ c    1790989824  2035175616  0.947702
 c
 c  Licensing:
 c
-c    This code is distributed under the GNU LGPL license. 
+c    This code is distributed under the GNU LGPL license.
 c
 c  Modified:
 c
@@ -693,7 +693,7 @@ cc TIMESTAMP prints out the current YMDHMS date as a timestamp.
 c
 c  Licensing:
 c
-c    This code is distributed under the GNU LGPL license. 
+c    This code is distributed under the GNU LGPL license.
 c
 c  Modified:
 c
@@ -724,8 +724,8 @@ c
       save month
 
       data month /
-     &  'January  ', 'February ', 'March    ', 'April    ', 
-     &  'May      ', 'June     ', 'July     ', 'August   ', 
+     &  'January  ', 'February ', 'March    ', 'April    ',
+     &  'May      ', 'June     ', 'July     ', 'August   ',
      &  'September', 'October  ', 'November ', 'December ' /
 
       call date_and_time ( date, time )
@@ -754,8 +754,8 @@ c
         end if
       end if
 
-      write ( *, 
-     &  '(i2,1x,a,1x,i4,2x,i2,a1,i2.2,a1,i2.2,a1,i3.3,1x,a)' ) 
+      write ( *,
+     &  '(i2,1x,a,1x,i4,2x,i2,a1,i2.2,a1,i2.2,a1,i3.3,1x,a)' )
      &  d, month(m), y, h, ':', n, ':', s, '.', mm, ampm
 
       return
@@ -772,7 +772,7 @@ c    The time integration is fully parallel.
 c
 c  Licensing:
 c
-c    This code is distributed under the GNU LGPL license. 
+c    This code is distributed under the GNU LGPL license.
 c
 c  Modified:
 c
@@ -815,7 +815,7 @@ c
 
       rmass = 1.0D+00 / mass
 
-c$omp parallel 
+c$omp parallel
 c$omp& shared ( acc, dt, f, nd, np, pos, rmass, vel )
 c$omp& private ( i, j )
 
@@ -823,10 +823,10 @@ c$omp do
       do j = 1, np
         do i = 1, nd
 
-          pos(i,j) = pos(i,j) 
+          pos(i,j) = pos(i,j)
      &      + vel(i,j) * dt + 0.5D+00 * acc(i,j) * dt * dt
 
-          vel(i,j) = vel(i,j) 
+          vel(i,j) = vel(i,j)
      &      + 0.5D+00 * dt * ( f(i,j) * rmass + acc(i,j) )
 
           acc(i,j) = f(i,j) * rmass
index 28f8f4777eb78c9df311e91d44c47c0f1af924eb..8f932059228afd13026e1f6b014baa57183ccb36 100644 (file)
@@ -1134,7 +1134,6 @@ tng_function_status tng_test_utility_functions(tng_trajectory_t traj, const char
                __FILE__, __LINE__);
         return(TNG_FAILURE);
     }
-
     stat = tng_util_trajectory_close(&traj);
     if(stat != TNG_SUCCESS)
     {
diff --git a/src/external/tng_io/src/tests/using/CMakeLists.txt b/src/external/tng_io/src/tests/using/CMakeLists.txt
new file mode 100644 (file)
index 0000000..35dcfcf
--- /dev/null
@@ -0,0 +1,96 @@
+# Test project to test building with libtng_io
+#
+# Combinations to test for full coverage:
+#   TEST_ZLIB=ON (22 combinations)
+#     ZLIB_LIBRARY=shared/static
+#     TEST_BUNDLING=ON (4 combinations)
+#       BUILD_SHARED_LIBS=ON/OFF
+#       TEST_EXECUTABLE=ON/OFF
+#     TEST_BUNDLING=OFF (7 combinations)
+#       TEST_EXECUTABLE=ON
+#         TNG_IO_DIR=sh.sh/st.sh/st.st
+#       TEST_EXECUTABLE=OFF
+#         BUILD_SHARED_LIBS=ON
+#           TNG_IO_DIR=sh.sh/st.sh/st.st
+#         BUILD_SHARED_LIBS=OFF
+#           TNG_IO_DIR=sh.sh
+#   TEST_ZLIB=OFF (27 combinations)
+#     TEST_BUNDLING=ON (12 combinations)
+#       ZLIB_LIBRARY=shared/static/none
+#       BUILD_SHARED_LIBS=ON/OFF
+#       TEST_EXECUTABLE=ON/OFF
+#     TEST_BUNDLING=OFF (15 combinations)
+#       TEST_EXECUTABLE=ON
+#         TNG_IO_DIR=sh.sh/sh.st/sh.int/st.sh/st.st/st.int
+#       TEST_EXECUTABLE=OFF
+#         BUILD_SHARED_LIBS=ON
+#           TNG_IO_DIR=sh.sh/sh.st/sh.int/st.sh/st.st/st.int
+#         BUILD_SHARED_LIBS=OFF
+#           TNG_IO_DIR=sh.sh/sh.st/sh.int
+#
+# Combinations that cannot work:
+#   TEST_ZLIB=ON, tng built with internal zlib
+#   TEST_ZLIB=ON, tng built with BUILD_SHARED_LIBS=ON + static zlib
+#   BUILD_SHARED_LIBS=ON, tng built as static (unless compiled with PIC)
+
+cmake_minimum_required(VERSION 3.1)
+
+project(tng_io_test)
+
+option(BUILD_SHARED_LIBS "Test building a shared library" ON)
+option(TEST_EXECUTABLE "Test building an executable instead of a library" OFF)
+option(TEST_BUNDLING "Test bundling tng" OFF)
+option(TEST_ZLIB "Test with zlib in using code" OFF)
+option(TEST_BUNDLED_ZLIB "Test bundling zlib with tng" OFF)
+if (NOT TEST_BUNDLING)
+    set(TEST_BUNDLED_ZLIB OFF)
+endif()
+
+if (TEST_ZLIB OR NOT TEST_BUNDLED_ZLIB)
+    find_package(ZLIB REQUIRED)
+endif()
+
+if (TEST_BUNDLING)
+    include(../../../BuildTNG.cmake)
+    if (TEST_BUNDLED_ZLIB)
+        message(STATUS "Bundling tng_io with internal ZLIB")
+        add_tng_io_library(tng_io OBJECT OWN_ZLIB)
+    else()
+        message(STATUS "Bundling tng_io with external ZLIB")
+        add_tng_io_library(tng_io OBJECT)
+    endif()
+    add_library(tng_io::tng_io ALIAS tng_io)
+else()
+    message(STATUS "Using external tng_io")
+    find_package(TNG_IO REQUIRED)
+endif()
+
+set(SOURCES use_tng.c)
+if (TEST_ZLIB)
+    message(STATUS "Using zlib in test application")
+    list(APPEND SOURCES use_zlib.c)
+else()
+    message(STATUS "Not using zlib in test application")
+    list(APPEND SOURCES dummy_zlib.c)
+endif()
+
+if (TEST_EXECUTABLE)
+    message(STATUS "Building an executable linked against tng_io")
+    add_executable(test_target main.c ${SOURCES})
+else()
+    message(STATUS "Building a library linked against tng_io")
+    add_library(test_target ${SOURCES})
+    install(TARGETS test_target EXPORT test DESTINATION lib)
+    install(EXPORT test DESTINATION lib/cmake/test)
+    add_executable(test_exe main.c)
+    target_link_libraries(test_exe PRIVATE test_target)
+endif()
+
+if (TEST_BUNDLING)
+    target_link_libraries(test_target PRIVATE $<BUILD_INTERFACE:tng_io::tng_io>)
+else()
+    target_link_libraries(test_target PRIVATE tng_io::tng_io)
+endif()
+if (TEST_ZLIB)
+    target_link_libraries(test_target PRIVATE ZLIB::ZLIB)
+endif()
diff --git a/src/external/tng_io/src/tests/using/dummy_zlib.c b/src/external/tng_io/src/tests/using/dummy_zlib.c
new file mode 100644 (file)
index 0000000..e28d040
--- /dev/null
@@ -0,0 +1,3 @@
+void test_zlib(void)
+{
+}
diff --git a/src/external/tng_io/src/tests/using/main.c b/src/external/tng_io/src/tests/using/main.c
new file mode 100644 (file)
index 0000000..a634fb3
--- /dev/null
@@ -0,0 +1,9 @@
+extern void test_tng(void);
+extern void test_zlib(void);
+
+int main(int argc, char *argv[])
+{
+    test_tng();
+    test_zlib();
+    return 0;
+}
diff --git a/src/external/tng_io/src/tests/using/use_tng.c b/src/external/tng_io/src/tests/using/use_tng.c
new file mode 100644 (file)
index 0000000..9fdd10f
--- /dev/null
@@ -0,0 +1,8 @@
+#include "tng/tng_io.h"
+
+void test_tng(void)
+{
+    tng_trajectory_t data;
+    char             buf[256];
+    tng_version(data, buf, 256);
+}
diff --git a/src/external/tng_io/src/tests/using/use_zlib.c b/src/external/tng_io/src/tests/using/use_zlib.c
new file mode 100644 (file)
index 0000000..f7958bd
--- /dev/null
@@ -0,0 +1,6 @@
+#include "zlib.h"
+
+void test_zlib(void)
+{
+    zlibVersion();
+}
index a42e624e1d6d6ac7711d909d84f0feaa7a5d0bc2..65f2ac435360c91ea2ccf0d6d497b630ed4d5180 100644 (file)
@@ -71,6 +71,7 @@ endfunction()
 
 add_subdirectory(gmxlib)
 add_subdirectory(mdlib)
+add_subdirectory(applied-forces)
 add_subdirectory(listed-forces)
 add_subdirectory(commandline)
 add_subdirectory(domdec)
@@ -121,13 +122,6 @@ list(APPEND LIBGROMACS_SOURCES ${GMXLIB_SOURCES} ${MDLIB_SOURCES} ${PROPERTY_SOU
 tmpi_get_source_list(THREAD_MPI_SOURCES ${CMAKE_SOURCE_DIR}/src/external/thread_mpi/src)
 list(APPEND LIBGROMACS_SOURCES ${THREAD_MPI_SOURCES})
 
-if(GMX_USE_TNG)
-    list(APPEND LIBGROMACS_SOURCES ${TNG_SOURCES})
-    if (NOT GMX_EXTERNAL_TNG)
-        tng_set_source_properties(WITH_ZLIB ${HAVE_ZLIB})
-    endif()
-endif()
-
 get_lmfit_properties(LMFIT_SOURCES LMFIT_LIBRARIES_TO_LINK LMFIT_INCLUDE_DIRECTORY LMFIT_INCLUDE_DIR_ORDER)
 include_directories(${LMFIT_INCLUDE_DIR_ORDER} SYSTEM "${LMFIT_INCLUDE_DIRECTORY}")
 list(APPEND LIBGROMACS_SOURCES ${LMFIT_SOURCES})
@@ -152,10 +146,13 @@ gmx_install_headers(
 set(GENERATED_VERSION_FILE utility/baseversion-gen.c)
 gmx_configure_version_file(
     utility/baseversion-gen.c.cmakein ${GENERATED_VERSION_FILE}
-    REMOTE_HASH SOURCE_FILE)
+    REMOTE_HASH)
 list(APPEND LIBGROMACS_SOURCES ${GENERATED_VERSION_FILE})
 
 if (GMX_USE_CUDA)
+    # Work around FindCUDA that prevents using target_link_libraries()
+    # with keywords otherwise...
+    set(CUDA_LIBRARIES PRIVATE ${CUDA_LIBRARIES})
     cuda_add_library(libgromacs ${LIBGROMACS_SOURCES})
 else()
     add_library(libgromacs ${LIBGROMACS_SOURCES})
@@ -172,15 +169,20 @@ if (HAS_NO_UNUSED_PARAMETER)
 endif()
 set_source_files_properties(selection/scanner.cpp PROPERTIES COMPILE_FLAGS "${_scanner_cpp_compiler_flags}")
 
+gmx_setup_tng_for_libgromacs()
+
 target_link_libraries(libgromacs
+                      PRIVATE
                       ${EXTRAE_LIBRARIES}
                       ${GMX_EXTRA_LIBRARIES}
-                      ${TNG_IO_LIBRARIES}
+                      ${GMX_COMMON_LIBRARIES}
                       ${FFT_LIBRARIES} ${LINEAR_ALGEBRA_LIBRARIES}
-                      ${XML_LIBRARIES}
                       ${LMFIT_LIBRARIES_TO_LINK}
                       ${THREAD_LIB} ${GMX_SHARED_LINKER_FLAGS} ${OPENCL_LIBRARIES}
-                      ${GMX_STDLIB_LIBRARIES})
+                      ${GMX_STDLIB_LIBRARIES}
+                      PUBLIC
+                      ${GMX_PUBLIC_LIBRARIES}
+                      )
 set_target_properties(libgromacs PROPERTIES
                       OUTPUT_NAME "gromacs${GMX_LIBS_SUFFIX}"
                       SOVERSION ${LIBRARY_SOVERSION_MAJOR}
index 2b0e0c1b56fd6986ee7818887acf9c16e09e3c6d..be081ad7656348dd48257e7938c8c7deeb389f09 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -280,14 +280,15 @@ AnalysisDataHandle::setPoint(int column, real value, real error, bool bPresent)
 
 
 void
-AnalysisDataHandle::setPoints(int firstColumn, int count, const real *values)
+AnalysisDataHandle::setPoints(int firstColumn, int count, const real *values,
+                              bool bPresent)
 {
     GMX_RELEASE_ASSERT(impl_ != NULL, "Invalid data handle used");
     GMX_RELEASE_ASSERT(impl_->currentFrame_ != NULL,
                        "setPoints() called without calling startFrame()");
     for (int i = 0; i < count; ++i)
     {
-        impl_->currentFrame_->setValue(firstColumn + i, values[i]);
+        impl_->currentFrame_->setValue(firstColumn + i, values[i], bPresent);
     }
 }
 
index 7d1b1997ed569fab2208f49a7030c3c3b9977814..bb135990e1edf737d204262ee9cc715c0acf3ca6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -326,13 +326,14 @@ class AnalysisDataHandle
          * \param[in] firstColumn  Zero-based column index.
          * \param[in] count        Number of columns to set.
          * \param[in] values       Value array of \p column items.
+         * \param[in] bPresent     Present flag to set for the column.
          *
-         * Equivalent to calling setPoint(firstColumn + i, values[i]) for
+         * Equivalent to calling setPoint(firstColumn + i, values[i], bPresent) for
          * i from 0 to count.
          *
          * Does not throw.
          */
-        void setPoints(int firstColumn, int count, const real *values);
+        void setPoints(int firstColumn, int count, const real *values, bool bPresent = true);
         /*! \brief
          * Finish data for the current point set.
          *
index f9e4d8dbb3919b8d5be36f2d2b9fb3e7afeffa30..4eb0a4afafc7c23c32a9c77977a80d5e23ecbf06 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -302,7 +302,7 @@ AnalysisDataModuleManager::addModule(AbstractAnalysisData      *data,
     {
         impl_->bAllowMissing_ = false;
     }
-    impl_->modules_.push_back(Impl::ModuleInfo(module));
+    impl_->modules_.emplace_back(module);
 }
 
 void
index 41ffc5f35c233263b5069c704949ac2e5147b585..8eb79be9884a2b9a074db12022a18ee66b5586c0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -574,8 +574,7 @@ AnalysisDataStorageFrameData::AnalysisDataStorageFrameData(
         for (int i = 0; i < baseData().dataSetCount(); ++i)
         {
             int columnCount = baseData().columnCount(i);
-            pointSets_.push_back(
-                    AnalysisDataPointSetInfo(offset, columnCount, i, 0));
+            pointSets_.emplace_back(offset, columnCount, i, 0);
             offset += columnCount;
         }
     }
@@ -625,9 +624,8 @@ AnalysisDataStorageFrameData::addPointSet(int dataSetIndex, int firstColumn,
     }
     else if (storageImpl().needStorage())
     {
-        pointSets_.push_back(
-                AnalysisDataPointSetInfo(values_.size(), valueCount,
-                                         dataSetIndex, firstColumn));
+        pointSets_.emplace_back(values_.size(), valueCount,
+                                dataSetIndex, firstColumn);
         std::copy(begin, end, std::back_inserter(values_));
     }
 }
index 9b9b2f468d142476098947a1fc85a9f169308264..586357097dd9571340d7c76736bc03e94ce4df97 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -280,7 +280,7 @@ AnalysisDataDisplacementModule::frameFinished(const AnalysisDataFrameHeader & /*
             i += _impl->max_store;
         }
         _impl->currValues_.clear();
-        _impl->currValues_.push_back(AnalysisDataValue(step * _impl->dt));
+        _impl->currValues_.emplace_back(step * _impl->dt);
         int k = 1;
         for (int j = 0; j < _impl->nmax; j += _impl->ndim, ++k)
         {
@@ -292,7 +292,7 @@ AnalysisDataDisplacementModule::frameFinished(const AnalysisDataFrameHeader & /*
                     - _impl->oldval[i + j + d];
                 dist2 += displ * displ;
             }
-            _impl->currValues_.push_back(AnalysisDataValue(dist2));
+            _impl->currValues_.emplace_back(dist2);
         }
         moduleManager().notifyPointsAdd(AnalysisDataPointSetRef(header, _impl->currValues_));
     }
index 1c64c4d5172f489a8f3fa0e7132cc4f3ac9e0a3a..9278d288c81c9c947fc73c368942fa9f31b4d2af 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -142,8 +142,8 @@ AnalysisDataLifetimeModule::dataStarted(AbstractAnalysisData *data)
     impl_->lifetimeHistograms_.reserve(data->dataSetCount());
     for (int i = 0; i < data->dataSetCount(); ++i)
     {
-        impl_->currentLifetimes_.push_back(std::vector<int>(data->columnCount(i), 0));
-        impl_->lifetimeHistograms_.push_back(std::deque<int>());
+        impl_->currentLifetimes_.emplace_back(data->columnCount(i), 0);
+        impl_->lifetimeHistograms_.emplace_back();
     }
 }
 
index e24160f28feec6d8e0342e26ed5d8a136acab2cc..11dfb933a8a29390cb1589eb7119225afa657257 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -282,7 +282,7 @@ AbstractPlotModule::setLegend(int nsets, const char * const *setname)
 void
 AbstractPlotModule::appendLegend(const char *setname)
 {
-    impl_->legend_.push_back(setname);
+    impl_->legend_.emplace_back(setname);
 }
 
 
@@ -535,7 +535,7 @@ AnalysisDataVectorPlotModule::pointsAdded(const AnalysisDataPointSetRef &points)
     {
         for (int d = 0; d < DIM; ++d)
         {
-            if (bWrite_[i])
+            if (bWrite_[d])
             {
                 writeValue(points.values()[i + d]);
             }
index 28abff7f0c7b841c03ee9af80bf23a45f22e8c4d..5ac37f1921a7137e081104d2b01af5841226b52e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -115,11 +115,11 @@ class AnalysisDataTestInputPointSet
         }
 
         //! Appends a value to this point set.
-        void addValue(real y) { values_.push_back(Value(y)); }
+        void addValue(real y) { values_.emplace_back(y); }
         //! Appends a value with an error estimate to this point set.
         void addValueWithError(real y, real error)
         {
-            values_.push_back(Value(y, error));
+            values_.emplace_back(y, error);
         }
 
     private:
diff --git a/src/gromacs/applied-forces/CMakeLists.txt b/src/gromacs/applied-forces/CMakeLists.txt
new file mode 100644 (file)
index 0000000..702e776
--- /dev/null
@@ -0,0 +1,41 @@
+#
+# This file is part of the GROMACS molecular simulation package.
+#
+# Copyright (c) 2015,2016, by the GROMACS development team, led by
+# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+# and including many others, as listed in the AUTHORS file in the
+# top-level source directory and at http://www.gromacs.org.
+#
+# GROMACS is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1
+# of the License, or (at your option) any later version.
+#
+# GROMACS is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with GROMACS; if not, see
+# http://www.gnu.org/licenses, or write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+#
+# If you want to redistribute modifications to GROMACS, please
+# consider that scientific software is very special. Version
+# control is crucial - bugs must be traceable. We will be happy to
+# consider code for inclusion in the official distribution, but
+# derived work must not be called official GROMACS. Details are found
+# in the README & COPYING files - if they are missing, get the
+# official version at http://www.gromacs.org.
+#
+# To help us fund GROMACS development, we humbly ask that you cite
+# the research papers on the package. Check out http://www.gromacs.org.
+
+gmx_add_libgromacs_sources(
+    electricfield.cpp
+    )
+
+if (BUILD_TESTING)
+    add_subdirectory(tests)
+endif()
diff --git a/src/gromacs/applied-forces/electricfield.cpp b/src/gromacs/applied-forces/electricfield.cpp
new file mode 100644 (file)
index 0000000..71f8421
--- /dev/null
@@ -0,0 +1,550 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2015,2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Declares data structure and utilities for electric fields
+ *
+ * \author David van der Spoel <david.vanderspoel@icm.uu.se>
+ * \ingroup module_applied_forces
+ */
+#include "gmxpre.h"
+
+#include "electricfield.h"
+
+#include <cmath>
+
+#include "gromacs/commandline/filenm.h"
+#include "gromacs/fileio/gmxfio.h"
+#include "gromacs/fileio/gmxfio-xdr.h"
+#include "gromacs/fileio/readinp.h"
+#include "gromacs/fileio/warninp.h"
+#include "gromacs/fileio/xvgr.h"
+#include "gromacs/gmxlib/network.h"
+#include "gromacs/math/units.h"
+#include "gromacs/math/vec.h"
+#include "gromacs/mdtypes/commrec.h"
+#include "gromacs/mdtypes/forcerec.h"
+#include "gromacs/mdtypes/inputrec.h"
+#include "gromacs/mdtypes/mdatom.h"
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/ioptionscontainerwithsections.h"
+#include "gromacs/options/optionsection.h"
+#include "gromacs/utility/compare.h"
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/keyvaluetreebuilder.h"
+#include "gromacs/utility/keyvaluetreetransform.h"
+#include "gromacs/utility/pleasecite.h"
+#include "gromacs/utility/strconvert.h"
+#include "gromacs/utility/stringutil.h"
+#include "gromacs/utility/txtdump.h"
+
+namespace gmx
+{
+
+namespace
+{
+
+/*! \internal
+ * \brief Declaration of storage unit for fields
+ */
+class ElectricFieldData
+{
+    public:
+        ElectricFieldData() : a_(0), omega_(0), t0_(0), sigma_(0)
+        {
+        }
+
+        /*! \brief
+         * Adds an option section to specify parameters for this field component.
+         */
+        void initMdpOptions(IOptionsContainerWithSections *options, const char *sectionName)
+        {
+            auto section = options->addSection(OptionSection(sectionName));
+            section.addOption(RealOption("E0").store(&a_));
+            section.addOption(RealOption("omega").store(&omega_));
+            section.addOption(RealOption("t0").store(&t0_));
+            section.addOption(RealOption("sigma").store(&sigma_));
+        }
+
+        /*! \brief Evaluates this field component at given time.
+         *
+         * \param[in] t The time to evualate at
+         * \return The electric field
+         */
+        real evaluate(real t) const
+        {
+            if (sigma_ > 0)
+            {
+                return a_ * (std::cos(omega_*(t-t0_))
+                             * std::exp(-square(t-t0_)/(2.0*square(sigma_))));
+            }
+            else
+            {
+                return a_ * std::cos(omega_*t);
+            }
+        }
+
+        /*! \brief Initiate the field values
+         *
+         * \param[in] a     Amplitude
+         * \param[in] omega Frequency
+         * \param[in] t0    Peak of the pulse
+         * \param[in] sigma Width of the pulse
+         */
+        void setField(real a, real omega, real t0, real sigma)
+        {
+            a_     = a;
+            omega_ = omega;
+            t0_    = t0;
+            sigma_ = sigma;
+        }
+
+        //! Return the amplitude
+        real a()     const { return a_; }
+        //! Return the frequency
+        real omega() const { return omega_; }
+        //! Return the time for the peak of the pulse
+        real t0()    const { return t0_; }
+        //! Return the width of the pulse (0 means inifinite)
+        real sigma() const { return sigma_; }
+
+    private:
+        //! Coeffient (V / nm)
+        real a_;
+        //! Frequency (1/ps)
+        real omega_;
+        //! Central time point (ps) for pulse
+        real t0_;
+        //! Width of pulse (ps, if zero there is no pulse)
+        real sigma_;
+};
+
+/*! \internal
+ * \brief Describe time dependent electric field
+ *
+ * Class that implements a force to be evaluated in mdrun.
+ * The electric field can be pulsed and oscillating, simply
+ * oscillating, or static, in each of X,Y,Z directions.
+ */
+class ElectricField : public IInputRecExtension, public IForceProvider
+{
+    public:
+        ElectricField() : fpField_(nullptr) {}
+
+        // From IInputRecExtension
+        virtual void doTpxIO(t_fileio *fio, bool bRead);
+        virtual void initMdpTransform(IKeyValueTreeTransformRules *transform);
+        virtual void initMdpOptions(IOptionsContainerWithSections *options);
+        virtual void broadCast(const t_commrec *cr);
+        virtual void compare(FILE                     *fp,
+                             const IInputRecExtension *field2,
+                             real                      reltol,
+                             real                      abstol);
+        virtual void printParameters(FILE *fp, int indent);
+        virtual void initOutput(FILE *fplog, int nfile, const t_filenm fnm[],
+                                bool bAppendFiles, const gmx_output_env_t *oenv);
+        virtual void finishOutput();
+        virtual void initForcerec(t_forcerec *fr);
+
+        //! \copydoc gmx::IForceProvider::calculateForces
+        virtual void calculateForces(const t_commrec  *cr,
+                                     const t_mdatoms  *atoms,
+                                     PaddedRVecVector *force,
+                                     double            t);
+
+    private:
+        //! Return whether or not to apply a field
+        bool isActive() const;
+
+        /*! \brief Add a component to the electric field
+         *
+         * The electric field has three spatial dimensions that are
+         * added to the data structure one at a time.
+         * \param[in] dim   Dimension, XX, YY, ZZ (0, 1, 2)
+         * \param[in] a     Amplitude of the field in V/nm
+         * \param[in] omega Frequency (1/ps)
+         * \param[in] t0    Time of pulse peak (ps)
+         * \param[in] sigma Width of peak (ps)
+         */
+        void setFieldTerm(int dim, real a, real omega, real t0, real sigma);
+
+        /*! \brief Return the field strength
+         *
+         * \param[in] dim The spatial direction
+         * \param[in] t   The time (ps)
+         * \return The field strength in V/nm units
+         */
+        real field(int dim, real t) const;
+
+        /*! \brief Return amplitude of field
+         *
+         * \param[in] dim Direction of the field (XX, YY, ZZ)
+         * \return Amplitude of the field
+         */
+        real a(int dim)     const { return efield_[dim].a(); }
+        /*! \brief Return frequency of field (1/ps)
+         *
+         * \param[in] dim Direction of the field (XX, YY, ZZ)
+         * \return Frequency of the field
+         */
+        real omega(int dim) const { return efield_[dim].omega(); }
+        /*! \brief Return time of pulse peak
+         *
+         * \param[in] dim Direction of the field (XX, YY, ZZ)
+         * \return Time of pulse peak
+         */
+        real t0(int dim) const { return efield_[dim].t0(); }
+        /*! \brief Return width of the pulse
+         *
+         * \param[in] dim Direction of the field (XX, YY, ZZ)
+         * \return Width of the pulse
+         */
+        real sigma(int dim) const { return efield_[dim].sigma(); }
+
+        /*! \brief Print the field components to a file
+         *
+         * \param[in] t   The time
+         * Will throw and exit with fatal error if file is not open.
+         */
+        void printComponents(double t) const;
+
+        //! The field strength in each dimension
+        ElectricFieldData efield_[DIM];
+        //! File pointer for electric field
+        FILE             *fpField_;
+};
+
+void ElectricField::doTpxIO(t_fileio *fio, bool bRead)
+{
+    // The content of the tpr file for this feature has
+    // been the same since gromacs 4.0 that was used for
+    // developing.
+    for (int j = 0; (j < DIM); j++)
+    {
+        int n = 0, nt = 0;
+        if (!bRead)
+        {
+            n = 1;
+            if (omega(j) != 0 || sigma(j) != 0 || t0(j) != 0)
+            {
+                nt = 1;
+            }
+        }
+        gmx_fio_do_int(fio, n);
+        gmx_fio_do_int(fio, nt);
+        std::vector<real> aa, phi, at, phit;
+        if (!bRead)
+        {
+            aa.push_back(a(j));
+            phi.push_back(t0(j));
+            at.push_back(omega(j));
+            phit.push_back(sigma(j));
+        }
+        else
+        {
+            aa.resize(n+1);
+            phi.resize(nt+1);
+            at.resize(nt+1);
+            phit.resize(nt+1);
+        }
+        gmx_fio_ndo_real(fio, aa.data(),  n);
+        gmx_fio_ndo_real(fio, phi.data(), n);
+        gmx_fio_ndo_real(fio, at.data(),  nt);
+        gmx_fio_ndo_real(fio, phit.data(), nt);
+        if (bRead && n > 0)
+        {
+            setFieldTerm(j, aa[0], at[0], phi[0], phit[0]);
+            if (n > 1 || nt > 1)
+            {
+                gmx_fatal(FARGS, "Can not handle tpr files with more than one electric field term per direction.");
+            }
+        }
+    }
+}
+
+//! Converts static parameters from mdp format to E0.
+real convertStaticParameters(const std::string &value)
+{
+    // TODO: Better context for the exceptions here (possibly
+    // also convert them to warning_errors or such).
+    const std::vector<std::string> sx = splitString(value);
+    if (sx.empty())
+    {
+        return 0.0;
+    }
+    const int n = fromString<int>(sx[0]);
+    if (n <= 0)
+    {
+        return 0.0;
+    }
+    if (n != 1)
+    {
+        GMX_THROW(InvalidInputError("Only one electric field term supported for each dimension"));
+    }
+    if (sx.size() != 3)
+    {
+        GMX_THROW(InvalidInputError("Expected exactly one electric field amplitude value"));
+    }
+    return fromString<real>(sx[1]);
+}
+
+//! Converts dynamic parameters from mdp format to (omega, t0, sigma).
+void convertDynamicParameters(gmx::KeyValueTreeObjectBuilder *builder,
+                              const std::string              &value)
+{
+    const std::vector<std::string> sxt = splitString(value);
+    if (sxt.empty())
+    {
+        return;
+    }
+    const int n = fromString<int>(sxt[0]);
+    switch (n)
+    {
+        case 1:
+            if (sxt.size() != 3)
+            {
+                GMX_THROW(InvalidInputError("Please specify 1 omega 0 for non-pulsed fields"));
+            }
+            builder->addValue<real>("omega", fromString<real>(sxt[1]));
+            break;
+        case 3:
+            if (sxt.size() != 7)
+            {
+                GMX_THROW(InvalidInputError("Please specify 1 omega 0 t0 0 sigma 0 for pulsed fields"));
+            }
+            builder->addValue<real>("omega", fromString<real>(sxt[1]));
+            builder->addValue<real>("t0", fromString<real>(sxt[3]));
+            builder->addValue<real>("sigma", fromString<real>(sxt[5]));
+            break;
+        default:
+            GMX_THROW(InvalidInputError("Incomprehensible input for electric field"));
+    }
+}
+
+void ElectricField::initMdpTransform(IKeyValueTreeTransformRules *rules)
+{
+    rules->addRule().from<std::string>("/E-x").to<real>("/electric-field/x/E0")
+        .transformWith(&convertStaticParameters);
+    rules->addRule().from<std::string>("/E-xt").toObject("/electric-field/x")
+        .transformWith(&convertDynamicParameters);
+    rules->addRule().from<std::string>("/E-y").to<real>("/electric-field/y/E0")
+        .transformWith(&convertStaticParameters);
+    rules->addRule().from<std::string>("/E-yt").toObject("/electric-field/y")
+        .transformWith(&convertDynamicParameters);
+    rules->addRule().from<std::string>("/E-z").to<real>("/electric-field/z/E0")
+        .transformWith(&convertStaticParameters);
+    rules->addRule().from<std::string>("/E-zt").toObject("/electric-field/z")
+        .transformWith(&convertDynamicParameters);
+}
+
+void ElectricField::initMdpOptions(IOptionsContainerWithSections *options)
+{
+    //CTYPE ("Format is E0 (V/nm), omega (1/ps), t0 (ps), sigma (ps) ");
+    auto section = options->addSection(OptionSection("electric-field"));
+    efield_[XX].initMdpOptions(&section, "x");
+    efield_[YY].initMdpOptions(&section, "y");
+    efield_[ZZ].initMdpOptions(&section, "z");
+}
+
+void ElectricField::broadCast(const t_commrec *cr)
+{
+    rvec a1, omega1, sigma1, t01;
+
+    if (MASTER(cr))
+    {
+        // Load the parameters read from tpr into temp vectors
+        for (int m = 0; m < DIM; m++)
+        {
+            a1[m]     = a(m);
+            omega1[m] = omega(m);
+            sigma1[m] = sigma(m);
+            t01[m]    = t0(m);
+        }
+    }
+    // Broadcasting the parameters
+    gmx_bcast(DIM*sizeof(a1[0]), a1, cr);
+    gmx_bcast(DIM*sizeof(omega1[0]), omega1, cr);
+    gmx_bcast(DIM*sizeof(t01[0]), t01, cr);
+    gmx_bcast(DIM*sizeof(sigma1[0]), sigma1, cr);
+
+    // And storing them locally
+    if (!MASTER(cr))
+    {
+        for (int m = 0; m < DIM; m++)
+        {
+            setFieldTerm(m, a1[m], omega1[m], t01[m], sigma1[m]);
+        }
+    }
+}
+
+void ElectricField::initOutput(FILE *fplog, int nfile, const t_filenm fnm[],
+                               bool bAppendFiles, const gmx_output_env_t *oenv)
+{
+    if (isActive())
+    {
+        please_cite(fplog, "Caleman2008a");
+
+        // Optional outpuf file showing the field, see manual.
+        if (opt2bSet("-field", nfile, fnm))
+        {
+            if (bAppendFiles)
+            {
+                fpField_ = gmx_fio_fopen(opt2fn("-field", nfile, fnm), "a+");
+            }
+            else
+            {
+                fpField_ = xvgropen(opt2fn("-field", nfile, fnm),
+                                    "Applied electric field", "Time (ps)",
+                                    "E (V/nm)", oenv);
+            }
+        }
+    }
+}
+
+void ElectricField::finishOutput()
+{
+    if (fpField_ != nullptr)
+    {
+        // This is opened sometimes with xvgropen, sometimes with
+        // gmx_fio_fopen, so we use the least common denominator for closing.
+        gmx_fio_fclose(fpField_);
+        fpField_ = nullptr;
+    }
+}
+
+void ElectricField::initForcerec(t_forcerec *fr)
+{
+    if (isActive())
+    {
+        fr->bF_NoVirSum = TRUE;
+        fr->efield      = this;
+    }
+}
+
+void ElectricField::printParameters(FILE *fp, int indent)
+{
+    const char *const dimension[DIM] = { "X", "Y", "Z" };
+    indent = pr_title(fp, indent, "ElectricField");
+    for (int m = 0; m < DIM; m++)
+    {
+        pr_indent(fp, indent);
+        fprintf(fp, "-%s E0 = %g omega = %g t0 = %g sigma = %g\n",
+                dimension[m], a(m), omega(m), t0(m), sigma(m));
+    }
+}
+
+void ElectricField::setFieldTerm(int dim, real a, real omega, real t0, real sigma)
+{
+    range_check(dim, 0, DIM);
+    efield_[dim].setField(a, omega, t0, sigma);
+}
+
+real ElectricField::field(int dim, real t) const
+{
+    return efield_[dim].evaluate(t);
+}
+
+bool ElectricField::isActive() const
+{
+    return (efield_[XX].a() != 0 ||
+            efield_[YY].a() != 0 ||
+            efield_[ZZ].a() != 0);
+}
+
+void ElectricField::compare(FILE                     *fp,
+                            const IInputRecExtension *other,
+                            real                      reltol,
+                            real                      abstol)
+{
+    GMX_ASSERT(dynamic_cast<const ElectricField *>(other) != nullptr,
+               "Invalid other type");
+    const ElectricField *f2 = static_cast<const ElectricField *>(other);
+    for (int m = 0; (m < DIM); m++)
+    {
+        char buf[256];
+
+        sprintf(buf, "inputrec->field[%d]", m);
+        cmp_real(fp, buf, -1, a(m), f2->a(m), reltol, abstol);
+        cmp_real(fp, buf, -1, omega(m), f2->omega(m), reltol, abstol);
+        cmp_real(fp, buf, -1, t0(m), f2->t0(m), reltol, abstol);
+        cmp_real(fp, buf, -1, sigma(m), f2->sigma(m), reltol, abstol);
+    }
+}
+
+void ElectricField::printComponents(double t) const
+{
+    fprintf(fpField_, "%10g  %10g  %10g  %10g\n", t,
+            field(XX, t), field(YY, t), field(ZZ, t));
+}
+
+void ElectricField::calculateForces(const t_commrec  *cr,
+                                    const t_mdatoms  *mdatoms,
+                                    PaddedRVecVector *force,
+                                    double            t)
+{
+    if (isActive())
+    {
+        rvec *f = as_rvec_array(force->data());
+
+        for (int m = 0; (m < DIM); m++)
+        {
+            real Ext = FIELDFAC*field(m, t);
+
+            if (Ext != 0)
+            {
+                // TODO: Check parallellism
+                for (int i = 0; i < mdatoms->homenr; ++i)
+                {
+                    // NOTE: Not correct with perturbed charges
+                    f[i][m] += mdatoms->chargeA[i]*Ext;
+                }
+            }
+        }
+        if (MASTER(cr) && fpField_ != nullptr)
+        {
+            printComponents(t);
+        }
+    }
+}
+
+}   // namespace
+
+std::unique_ptr<IInputRecExtension> createElectricFieldModule()
+{
+    return std::unique_ptr<IInputRecExtension>(new ElectricField());
+}
+
+} // namespace gmx
diff --git a/src/gromacs/applied-forces/electricfield.h b/src/gromacs/applied-forces/electricfield.h
new file mode 100644 (file)
index 0000000..9f1cce8
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2015,2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+#ifndef GMX_APPLIED_FORCES_ELECTRICFIELD_H
+#define GMX_APPLIED_FORCES_ELECTRICFIELD_H
+
+#include <memory>
+
+namespace gmx
+{
+
+class IInputRecExtension;
+
+/*! \brief
+ * Creates a module for an external electric field.
+ *
+ * The returned class describes the time dependent electric field that can
+ * be applied to all charges in a simulation. The field is described
+ * by the following:
+ *     E(t) = A cos(omega*(t-t0))*exp(-sqr(t-t0)/(2.0*sqr(sigma)));
+ * If sigma = 0 there is no pulse and we have instead
+ *     E(t) = A cos(omega*t)
+ *
+ * force is kJ mol^-1 nm^-1 = e * kJ mol^-1 nm^-1 / e
+ *
+ * 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-consistent electric field into PME.
+ */
+std::unique_ptr<IInputRecExtension> createElectricFieldModule();
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/applied-forces/tests/CMakeLists.txt b/src/gromacs/applied-forces/tests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3788986
--- /dev/null
@@ -0,0 +1,37 @@
+#
+# This file is part of the GROMACS molecular simulation package.
+#
+# Copyright (c) 2015,2016, by the GROMACS development team, led by
+# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+# and including many others, as listed in the AUTHORS file in the
+# top-level source directory and at http://www.gromacs.org.
+#
+# GROMACS is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1
+# of the License, or (at your option) any later version.
+#
+# GROMACS is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with GROMACS; if not, see
+# http://www.gnu.org/licenses, or write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+#
+# If you want to redistribute modifications to GROMACS, please
+# consider that scientific software is very special. Version
+# control is crucial - bugs must be traceable. We will be happy to
+# consider code for inclusion in the official distribution, but
+# derived work must not be called official GROMACS. Details are found
+# in the README & COPYING files - if they are missing, get the
+# official version at http://www.gromacs.org.
+#
+# To help us fund GROMACS development, we humbly ask that you cite
+# the research papers on the package. Check out http://www.gromacs.org.
+
+gmx_add_unit_test(AppliedForcesUnitTest applied-forces-test
+                  electricfield.cpp
+                )
diff --git a/src/gromacs/applied-forces/tests/electricfield.cpp b/src/gromacs/applied-forces/tests/electricfield.cpp
new file mode 100644 (file)
index 0000000..cf8bb05
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2015,2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Tests for functionality of the "angle" trajectory analysis module.
+ *
+ * \author David van der Spoel <david.vanderspoel@icm.uu.se>
+ * \ingroup module_applied_forces
+ */
+#include "gmxpre.h"
+
+#include "gromacs/applied-forces/electricfield.h"
+
+#include <gtest/gtest.h>
+
+#include "gromacs/gmxlib/network.h"
+#include "gromacs/math/vec.h"
+#include "gromacs/mdlib/forcerec.h"
+#include "gromacs/mdrunutility/mdmodules.h"
+#include "gromacs/mdtypes/forcerec.h"
+#include "gromacs/mdtypes/inputrec.h"
+#include "gromacs/mdtypes/mdatom.h"
+#include "gromacs/options/options.h"
+#include "gromacs/options/treesupport.h"
+#include "gromacs/utility/keyvaluetreebuilder.h"
+#include "gromacs/utility/keyvaluetreetransform.h"
+#include "gromacs/utility/real.h"
+#include "gromacs/utility/smalloc.h"
+#include "gromacs/utility/stringcompare.h"
+#include "gromacs/utility/stringutil.h"
+
+#include "testutils/testasserts.h"
+
+namespace
+{
+
+/********************************************************************
+ * ElectricFieldTest
+ */
+
+class ElectricFieldTest : public ::testing::Test
+{
+    public:
+        ElectricFieldTest() {}
+
+        void test(int  dim,
+                  real E0,
+                  real omega,
+                  real t0,
+                  real sigma,
+                  real expectedValue)
+        {
+            gmx::test::FloatingPointTolerance tolerance(
+                    gmx::test::relativeToleranceAsFloatingPoint(1.0, 0.005));
+            gmx::MDModules                    module;
+            t_inputrec *inputrec = module.inputrec();
+
+            // Prepare MDP inputs
+            const char *dimXYZ[3] = { "x", "y", "z" };
+            GMX_RELEASE_ASSERT((dim >= 0 && dim < 3), "Dimension should be 0, 1 or 2");
+
+            gmx::KeyValueTreeBuilder     mdpValues;
+            mdpValues.rootObject().addValue(gmx::formatString("E%s", dimXYZ[dim]),
+                                            gmx::formatString("1 %g 0", E0));
+            mdpValues.rootObject().addValue(gmx::formatString("E%s-t", dimXYZ[dim]),
+                                            gmx::formatString("3 %g 0 %g 0 %g 0", omega, t0, sigma));
+
+            gmx::KeyValueTreeTransformer transform;
+            transform.rules()->addRule()
+                .keyMatchType("/", gmx::StringCompareType::CaseAndDashInsensitive);
+            inputrec->efield->initMdpTransform(transform.rules());
+            gmx::Options                 options;
+            inputrec->efield->initMdpOptions(&options);
+            auto                         result = transform.transform(mdpValues.build(), nullptr);
+            gmx::assignOptionsFromKeyValueTree(&options, result.object(), nullptr);
+
+            t_mdatoms        md;
+            PaddedRVecVector f = { { 0, 0, 0 } };
+            md.homenr = 1;
+            snew(md.chargeA, md.homenr);
+            md.chargeA[0] = 1;
+
+            t_commrec  *cr       = init_commrec();
+            t_forcerec *forcerec = mk_forcerec();
+            inputrec->efield->initForcerec(forcerec);
+            forcerec->efield->calculateForces(cr, &md, &f, 0);
+            done_commrec(cr);
+            EXPECT_REAL_EQ_TOL(f[0][dim], expectedValue, tolerance);
+            sfree(forcerec);
+            sfree(md.chargeA);
+        }
+};
+
+TEST_F(ElectricFieldTest, Static)
+{
+    test(0, 1, 0, 0, 0, 96.4853363);
+}
+
+TEST_F(ElectricFieldTest, Oscillating)
+{
+    test(0, 1, 5, 0.2, 0, 96.4853363);
+}
+
+TEST_F(ElectricFieldTest, Pulsed)
+{
+    test(0, 1, 5, 0.5, 1, -68.215782);
+}
+
+} // namespace
index 054b5b3530ee4b2a37f7ff8b9907c7d07a9b9b17..0a2ceac2ec1e64441020e7ff76bb2caba326739e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -108,7 +108,7 @@ class RootHelpTopic : public AbstractCompositeHelpTopic
         {
             if (bExported)
             {
-                exportedTopics_.push_back(topic->name());
+                exportedTopics_.emplace_back(topic->name());
             }
             addSubTopic(std::move(topic));
         }
@@ -743,7 +743,7 @@ void HelpExportCompletion::exportModuleHelp(
         const std::string                 & /*tag*/,
         const std::string                 & /*displayName*/)
 {
-    modules_.push_back(module.name());
+    modules_.emplace_back(module.name());
     {
         CommandLineHelpContext context(&bashWriter_);
         // We use the display name to pass the name of the module to the
@@ -949,7 +949,7 @@ int CommandLineHelpModule::run(int argc, char *argv[])
 
     const char *const exportFormats[] = { "rst", "completion" };
     std::string       exportFormat;
-    Options           options(NULL, NULL);
+    Options           options;
     options.addOption(StringOption("export").store(&exportFormat)
                           .enumValue(exportFormats));
     CommandLineParser(&options).parse(&argc, argv);
index 275f70fb9d4fe1363b27ef483b1b46cbd413a384..4756ebe4a8b2524ba2b24ef553214c5568bec63c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -136,7 +136,7 @@ class OptionsFilter : public OptionsVisitor
                             IOptionsFormatter         *formatter,
                             const Options             &options);
 
-        virtual void visitSubSection(const Options &section);
+        virtual void visitSection(const OptionSectionInfo &section);
         virtual void visitOption(const OptionInfo &option);
 
     private:
@@ -153,13 +153,13 @@ void OptionsFilter::formatSelected(FilterType                 type,
 {
     formatter_  = formatter;
     filterType_ = type;
-    visitSubSection(options);
+    visitSection(options.rootSection());
 }
 
-void OptionsFilter::visitSubSection(const Options &section)
+void OptionsFilter::visitSection(const OptionSectionInfo &section)
 {
     OptionsIterator iterator(section);
-    iterator.acceptSubSections(this);
+    iterator.acceptSections(this);
     iterator.acceptOptions(this);
 }
 
@@ -248,27 +248,9 @@ void formatOptionNameAndValue(const OptionInfo &option, std::string *name,
 }
 
 //! Formats the default option value as a string.
-std::string
-defaultOptionValue(const OptionInfo &option)
+std::string defaultOptionValue(const OptionInfo &option)
 {
-    if (option.valueCount() == 0
-        || (option.valueCount() == 1 && option.formatValue(0).empty()))
-    {
-        return option.formatDefaultValueIfSet();
-    }
-    else
-    {
-        std::string result;
-        for (int i = 0; i < option.valueCount(); ++i)
-        {
-            if (i != 0)
-            {
-                result.append(" ");
-            }
-            result.append(option.formatValue(i));
-        }
-        return result;
-    }
+    return joinStrings(option.defaultValuesAsStrings(), " ");
 }
 
 //! Formats the flags for a file option as a string.
index 71180bfbb52eb2483d8e412fda0536fe3d720738..82b14fe19c628b57107877f6f599a7f1b0555d0b 100644 (file)
@@ -153,7 +153,7 @@ class CMainCommandLineModule : public ICommandLineModule
  */
 
 CommandLineCommonOptionsHolder::CommandLineCommonOptionsHolder()
-    : options_(NULL, NULL), bHelp_(false), bHidden_(false),
+    : bHelp_(false), bHidden_(false),
       bQuiet_(false), bVersion_(false), bCopyright_(true),
       niceLevel_(19), bNiceSet_(false), bBackup_(true), bFpexcept_(false),
       debugLevel_(0)
index ed87db95422c6780692fc6c42238c2367ba97836..b4d45d37556010611c2e8accdb319a7a28f08127 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -154,7 +154,7 @@ void CommandLineOptionsModule::writeHelp(const CommandLineHelpContext &context)
         moduleGuard = factory_();
         module      = moduleGuard.get();
     }
-    Options                          options(name(), shortDescription());
+    Options                          options;
     OptionsBehaviorCollection        behaviors(&options);
     CommandLineOptionsModuleSettings settings(&behaviors);
     module->initOptions(&options, &settings);
@@ -166,7 +166,7 @@ void CommandLineOptionsModule::writeHelp(const CommandLineHelpContext &context)
 void CommandLineOptionsModule::parseOptions(int argc, char *argv[])
 {
     FileNameOptionManager fileoptManager;
-    Options               options(name_, description_);
+    Options               options;
 
     options.addManager(&fileoptManager);
 
index 8fd3da8f470efc9d4d7b8f477524192962d26afb..dcbb501dc26947e58930554c225334a0414e01a2 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -210,7 +210,7 @@ int getDefaultXvgFormat(gmx::ConstArrayRef<const char *> xvgFormats)
             std::find(xvgFormats.begin(), xvgFormats.end(), std::string(select));
         if (i != xvgFormats.end())
         {
-            return i - xvgFormats.begin();
+            return std::distance(xvgFormats.begin(), i);
         }
         else
         {
@@ -344,7 +344,7 @@ void OptionsAdapter::filenmToOptions(Options *options, t_filenm *fnm)
         GMX_RELEASE_ASSERT(defType != efNR,
                            "File name option specifies an invalid extension");
     }
-    fileNameOptions_.push_back(FileNameData(fnm));
+    fileNameOptions_.emplace_back(fnm);
     FileNameData &data = fileNameOptions_.back();
     data.optionInfo = options->addOption(
                 FileNameOption(name).storeVector(&data.values)
@@ -361,7 +361,7 @@ void OptionsAdapter::pargsToOptions(Options *options, t_pargs *pa)
     const bool        bHidden = startsWith(pa->desc, "HIDDEN");
     const char *const name    = &pa->option[1];
     const char *const desc    = (bHidden ? &pa->desc[6] : pa->desc);
-    programArgs_.push_back(ProgramArgData(pa));
+    programArgs_.emplace_back(pa);
     ProgramArgData   &data = programArgs_.back();
     switch (pa->type)
     {
@@ -494,7 +494,7 @@ gmx_bool parse_common_args(int *argc, char *argv[], unsigned long Flags,
         bool                            bView         = false;
         int                             xvgFormat     = 0;
         gmx::OptionsAdapter             adapter(*argc, argv);
-        gmx::Options                    options(NULL, NULL);
+        gmx::Options                    options;
         gmx::OptionsBehaviorCollection  behaviors(&options);
         gmx::FileNameOptionManager      fileOptManager;
 
index be1cd70d97fcfa30844436087c35ef19e4c2cf11..88d64ab8c627d2060d5abbedaabc4e905ff21177 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -56,6 +56,7 @@
 #include "gromacs/fileio/filetypes.h"
 #include "gromacs/options/basicoptions.h"
 #include "gromacs/options/filenameoption.h"
+#include "gromacs/options/options.h"
 #include "gromacs/options/optionsvisitor.h"
 #include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/exceptions.h"
@@ -74,10 +75,10 @@ class OptionsListWriter : public OptionsVisitor
     public:
         const std::string &optionList() const { return optionList_; }
 
-        virtual void visitSubSection(const Options &section)
+        virtual void visitSection(const OptionSectionInfo &section)
         {
             OptionsIterator iterator(section);
-            iterator.acceptSubSections(this);
+            iterator.acceptSections(this);
             iterator.acceptOptions(this);
         }
         virtual void visitOption(const OptionInfo &option)
@@ -109,10 +110,10 @@ class OptionCompletionWriter : public OptionsVisitor
     public:
         explicit OptionCompletionWriter(TextWriter *out) : out_(*out) {}
 
-        virtual void visitSubSection(const Options &section)
+        virtual void visitSection(const OptionSectionInfo &section)
         {
             OptionsIterator iterator(section);
-            iterator.acceptSubSections(this);
+            iterator.acceptSections(this);
             iterator.acceptOptions(this);
         }
         virtual void visitOption(const OptionInfo &option);
@@ -237,12 +238,12 @@ void ShellCompletionWriter::writeModuleCompletions(
     out.writeLine("COMPREPLY=()");
 
     OptionsListWriter listWriter;
-    listWriter.visitSubSection(options);
+    listWriter.visitSection(options.rootSection());
     out.writeLine(formatString("if (( $COMP_CWORD <= 1 )) || [[ $c == -* ]]; then COMPREPLY=( $(compgen -S ' '  -W $'%s' -- $c)); return 0; fi", listWriter.optionList().c_str()));
 
     out.writeLine("case \"$p\" in");
     OptionCompletionWriter optionWriter(&out);
-    optionWriter.visitSubSection(options);
+    optionWriter.visitSection(options.rootSection());
     out.writeLine("esac }");
 }
 
@@ -261,7 +262,7 @@ void ShellCompletionWriter::writeWrapperCompletions(
     impl_->file_->writeLine("if (( i == COMP_CWORD )); then");
     impl_->file_->writeLine("c=${COMP_WORDS[COMP_CWORD]}");
     OptionsListWriter lister;
-    lister.visitSubSection(options);
+    lister.visitSection(options.rootSection());
     std::string       completions(lister.optionList());
     for (ModuleNameList::const_iterator i = modules.begin();
          i != modules.end(); ++i)
index 2e9be1a9086bf9c5ab148b9939adc5c765cae608..c05cc559b84288c353640f9f8d690f04e69921ac 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by
+# Copyright (c) 2012,2013,2014,2015,2016, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -60,11 +60,3 @@ gmx_add_unit_test(CommandLineUnitTests commandline-test
                   cmdlineprogramcontext.cpp
                   pargs.cpp
                   $<TARGET_OBJECTS:onlinehelp-test-shared>)
-
-if (CMAKE_CXX_COMPILER_ID MATCHES "XL")
-    # This suppression stops a very verbose cascade of messages about the
-    # mocks, which is probably a compiler issue.
-    #   1540-2924 (W) Cannot pass an argument of non-POD class type "const gmx::CommandLineHelpContext" through ellipsis.
-    set_property(SOURCE cmdlinehelpmodule.cpp cmdlinemodulemanager.cpp cmdlinemodulemanagertest.cpp
-                 PROPERTY COMPILE_FLAGS "-qsuppress=1540-2924")
-endif()
index ae34edf40f6dcae859d0dabda4cce221c2498558..84f70e7891cdbb82565e95f341fb5c33ad32fd07 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -101,7 +101,7 @@ TEST_F(CommandLineHelpWriterTest, HandlesOptionTypes)
 {
     using namespace gmx;
 
-    Options options("test", "Short Description");
+    Options options;
     options.addOption(BooleanOption("bool").description("Boolean option")
                           .defaultValue(true));
     options.addOption(BooleanOption("hidden").description("Hidden option")
@@ -166,7 +166,7 @@ TEST_F(CommandLineHelpWriterTest, HandlesDefaultValuesFromVariables)
 {
     using namespace gmx;
 
-    Options options("test", "Short Description");
+    Options options;
 
     bool    bValue = true;
     options.addOption(BooleanOption("bool").description("Boolean option")
@@ -181,7 +181,7 @@ TEST_F(CommandLineHelpWriterTest, HandlesDefaultValuesFromVariables)
                           .store(iavalue).valueCount(2));
 
     std::vector<std::string> svalues;
-    svalues.push_back("foo");
+    svalues.emplace_back("foo");
     options.addOption(StringOption("str").description("String option")
                           .storeVector(&svalues).multiValue());
 
@@ -204,7 +204,7 @@ TEST_F(CommandLineHelpWriterTest, HandlesLongFileOptions)
     using gmx::eftGenericData;
     using gmx::eftTrajectory;
 
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     options.addOption(FileNameOption("f")
                           .description("File name option with a long value")
                           .filetype(eftTrajectory).inputFile().required()
@@ -240,7 +240,7 @@ TEST_F(CommandLineHelpWriterTest, HandlesLongOptions)
     using gmx::DoubleOption;
     using gmx::StringOption;
 
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     options.addOption(BooleanOption("longboolean")
                           .description("Boolean option with a long name")
                           .defaultValue(true));
@@ -248,8 +248,8 @@ TEST_F(CommandLineHelpWriterTest, HandlesLongOptions)
     options.addOption(DoubleOption("dvec").description("Double vector option")
                           .vector().store(dblvec));
     std::vector<std::string> values;
-    values.push_back("A very long string value that overflows even the description column");
-    values.push_back("Another very long string value that overflows even the description column");
+    values.emplace_back("A very long string value that overflows even the description column");
+    values.emplace_back("Another very long string value that overflows even the description column");
     options.addOption(StringOption("string")
                           .description("String option with very long values (may "
                                        "be less relevant with selections having "
@@ -270,7 +270,7 @@ TEST_F(CommandLineHelpWriterTest, HandlesSelectionOptions)
     using gmx::SelectionFileOption;
     using gmx::SelectionOption;
 
-    gmx::Options                options(NULL, NULL);
+    gmx::Options                options;
     gmx::SelectionCollection    selections;
     gmx::SelectionOptionManager manager(&selections);
     options.addManager(&manager);
@@ -298,7 +298,7 @@ TEST_F(CommandLineHelpWriterTest, HandlesOptionGroups)
 {
     using gmx::IntegerOption;
 
-    gmx::Options            options(NULL, NULL);
+    gmx::Options            options;
     gmx::IOptionsContainer &group1 = options.addGroup();
     gmx::IOptionsContainer &group2 = options.addGroup();
     group2.addOption(IntegerOption("sub2").description("Option in group 2"));
@@ -321,7 +321,7 @@ TEST_F(CommandLineHelpWriterTest, HandlesHelpText)
     };
     using gmx::IntegerOption;
 
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     options.addOption(IntegerOption("int").description("Integer option")
                           .defaultValue(2));
 
index 719e69d34f71917e67a1c1a2198387b44eee4e99..d9f973d0117eeace823313c28981a5d8f23a0a51 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -76,8 +76,7 @@ class CommandLineParserTest : public ::testing::Test
 };
 
 CommandLineParserTest::CommandLineParserTest()
-    : options_(NULL, NULL), parser_(&options_),
-      flag_(false), ivalue1p_(0), ivalue12_(0)
+    : parser_(&options_), flag_(false), ivalue1p_(0), ivalue12_(0)
 {
     using gmx::BooleanOption;
     using gmx::IntegerOption;
index 376908bdb03ab9ea391d7bf987fe487980f9d628..4308ac80e7ba754176b845939787b4cfd0e38b14 100644 (file)
@@ -146,7 +146,7 @@ TEST_F(CommandLineProgramContextTest, FindsBinaryFromPath)
 TEST_F(CommandLineProgramContextTest, FindsBinaryFromCurrentDirectory)
 {
     env_->workingDirectory_ = Path::join(env_->getWorkingDirectory(), "bin");
-    env_->path_.push_back("");
+    env_->path_.emplace_back("");
     testBinaryPathSearch("test-exe");
 }
 
index cf6edc3d04f1a8f82885ff7841dfce05e4824c0c..28cb5ad88d0c690c08d250ecf5c8d4ab60632430 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -350,7 +350,7 @@ TEST_F(ParseCommonArgsTest, ParsesFileArgsWithDefaults)
     parseFromArray(cmdline, 0, fnm, gmx::EmptyArrayRef());
     EXPECT_STREQ("topol.tpr", ftp2fn(efTPS, nfile(), fnm));
     EXPECT_STREQ("traj.xtc", opt2fn("-f2", nfile(), fnm));
-    EXPECT_NULL(opt2fn_null("-f2", nfile(), fnm));
+    EXPECT_EQ(nullptr, opt2fn_null("-f2", nfile(), fnm));
     EXPECT_STREQ("trj3.xtc", opt2fn("-f3", nfile(), fnm));
     EXPECT_STREQ("out.xvg", opt2fn("-o", nfile(), fnm));
     EXPECT_STREQ("outm.xvg", opt2fn("-om", nfile(), fnm));
@@ -551,9 +551,9 @@ TEST_F(ParseCommonArgsTest, HandlesNonReadNode)
         "test", "-f", "-f2", "other"
     };
     parseFromArray(cmdline, PCA_NOT_READ_NODE, fnm, gmx::EmptyArrayRef());
-    EXPECT_NULL(fnm[0].fns);
-    EXPECT_NULL(fnm[1].fns);
-    EXPECT_NULL(fnm[2].fns);
+    EXPECT_EQ(nullptr, fnm[0].fns);
+    EXPECT_EQ(nullptr, fnm[1].fns);
+    EXPECT_EQ(nullptr, fnm[2].fns);
     done_filenms(nfile(), fnm);
 }
 
@@ -568,9 +568,9 @@ TEST_F(ParseCommonArgsTest, HandlesNonReadNodeWithDefaultFileName)
         "test", "-deffnm", "def", "-f", "-f2", "other"
     };
     parseFromArray(cmdline, PCA_CAN_SET_DEFFNM | PCA_NOT_READ_NODE, fnm, gmx::EmptyArrayRef());
-    EXPECT_NULL(fnm[0].fns);
-    EXPECT_NULL(fnm[1].fns);
-    EXPECT_NULL(fnm[2].fns);
+    EXPECT_EQ(nullptr, fnm[0].fns);
+    EXPECT_EQ(nullptr, fnm[1].fns);
+    EXPECT_EQ(nullptr, fnm[2].fns);
     done_filenms(nfile(), fnm);
 }
 
index 97d4a8c62d641ad5517816823258d99cbae1fa6a..acc01a24957f5659e48b0da5fbd396102a4f9d01 100644 (file)
@@ -87,36 +87,42 @@ enum {
 };
 
 /*! \brief Routine to compute ACF using FFT. */
-static void low_do_four_core(int nfour, int nframes, real c1[], real cfour[],
+static void low_do_four_core(int nframes, real c1[], real cfour[],
                              int nCos)
 {
     int  i = 0;
-
+    std::vector<std::vector<real> > data;
+    data.resize(1);
+    data[0].resize(nframes, 0);
     switch (nCos)
     {
         case enNorm:
             for (i = 0; (i < nframes); i++)
             {
-                cfour[i] = c1[i];
+                data[0][i] = c1[i];
             }
             break;
         case enCos:
             for (i = 0; (i < nframes); i++)
             {
-                cfour[i] = cos(c1[i]);
+                data[0][i] = cos(c1[i]);
             }
             break;
         case enSin:
             for (i = 0; (i < nframes); i++)
             {
-                cfour[i] = sin(c1[i]);
+                data[0][i] = sin(c1[i]);
             }
             break;
         default:
             gmx_fatal(FARGS, "nCos = %d, %s %d", nCos, __FILE__, __LINE__);
     }
 
-    many_auto_correl(1, nframes, nfour, &cfour);
+    many_auto_correl(&data);
+    for (i = 0; (i < nframes); i++)
+    {
+        cfour[i] = data[0][i];
+    }
 }
 
 /*! \brief Routine to comput ACF without FFT. */
@@ -332,22 +338,22 @@ static void dump_tmp(char *s, int n, real c[])
 }
 
 /*! \brief High level ACF routine. */
-void do_four_core(unsigned long mode, int nfour, int nf2, int nframes,
-                  real c1[], real csum[], real ctmp[])
+static void do_four_core(unsigned long mode, int nframes,
+                         real c1[], real csum[], real ctmp[])
 {
     real   *cfour;
     char    buf[32];
     real    fac;
     int     j, m, m1;
 
-    snew(cfour, nfour);
+    snew(cfour, nframes);
 
     if (MODE(eacNormal))
     {
         /********************************************
          *  N O R M A L
          ********************************************/
-        low_do_four_core(nfour, nf2, c1, csum, enNorm);
+        low_do_four_core(nframes, c1, csum, enNorm);
     }
     else if (MODE(eacCos))
     {
@@ -357,21 +363,21 @@ void do_four_core(unsigned long mode, int nfour, int nf2, int nframes,
         /* Copy the data to temp array. Since we need it twice
          * we can't overwrite original.
          */
-        for (j = 0; (j < nf2); j++)
+        for (j = 0; (j < nframes); j++)
         {
             ctmp[j] = c1[j];
         }
 
         /* Cosine term of AC function */
-        low_do_four_core(nfour, nf2, ctmp, cfour, enCos);
-        for (j = 0; (j < nf2); j++)
+        low_do_four_core(nframes, ctmp, cfour, enCos);
+        for (j = 0; (j < nframes); j++)
         {
             c1[j]  = cfour[j];
         }
 
         /* Sine term of AC function */
-        low_do_four_core(nfour, nf2, ctmp, cfour, enSin);
-        for (j = 0; (j < nf2); j++)
+        low_do_four_core(nframes, ctmp, cfour, enSin);
+        for (j = 0; (j < nframes); j++)
         {
             c1[j]  += cfour[j];
             csum[j] = c1[j];
@@ -418,34 +424,34 @@ void do_four_core(unsigned long mode, int nfour, int nf2, int nframes,
         /* Because of normalization the number of -0.5 to subtract
          * depends on the number of data points!
          */
-        for (j = 0; (j < nf2); j++)
+        for (j = 0; (j < nframes); j++)
         {
-            csum[j]  = -0.5*(nf2-j);
+            csum[j]  = -0.5*(nframes-j);
         }
 
         /***** DIAGONAL ELEMENTS ************/
         for (m = 0; (m < DIM); m++)
         {
             /* Copy the vector data in a linear array */
-            for (j = 0; (j < nf2); j++)
+            for (j = 0; (j < nframes); j++)
             {
                 ctmp[j]  = gmx::square(c1[DIM*j+m]);
             }
             if (debug)
             {
                 sprintf(buf, "c1diag%d.xvg", m);
-                dump_tmp(buf, nf2, ctmp);
+                dump_tmp(buf, nframes, ctmp);
             }
 
-            low_do_four_core(nfour, nf2, ctmp, cfour, enNorm);
+            low_do_four_core(nframes, ctmp, cfour, enNorm);
 
             if (debug)
             {
                 sprintf(buf, "c1dfout%d.xvg", m);
-                dump_tmp(buf, nf2, cfour);
+                dump_tmp(buf, nframes, cfour);
             }
             fac = 1.5;
-            for (j = 0; (j < nf2); j++)
+            for (j = 0; (j < nframes); j++)
             {
                 csum[j] += fac*(cfour[j]);
             }
@@ -455,7 +461,7 @@ void do_four_core(unsigned long mode, int nfour, int nf2, int nframes,
         {
             /* Copy the vector data in a linear array */
             m1 = (m+1) % DIM;
-            for (j = 0; (j < nf2); j++)
+            for (j = 0; (j < nframes); j++)
             {
                 ctmp[j] = c1[DIM*j+m]*c1[DIM*j+m1];
             }
@@ -463,16 +469,16 @@ void do_four_core(unsigned long mode, int nfour, int nf2, int nframes,
             if (debug)
             {
                 sprintf(buf, "c1off%d.xvg", m);
-                dump_tmp(buf, nf2, ctmp);
+                dump_tmp(buf, nframes, ctmp);
             }
-            low_do_four_core(nfour, nf2, ctmp, cfour, enNorm);
+            low_do_four_core(nframes, ctmp, cfour, enNorm);
             if (debug)
             {
                 sprintf(buf, "c1ofout%d.xvg", m);
-                dump_tmp(buf, nf2, cfour);
+                dump_tmp(buf, nframes, cfour);
             }
             fac = 3.0;
-            for (j = 0; (j < nf2); j++)
+            for (j = 0; (j < nframes); j++)
             {
                 csum[j] += fac*cfour[j];
             }
@@ -493,19 +499,19 @@ void do_four_core(unsigned long mode, int nfour, int nf2, int nframes,
          * First for XX, then for YY, then for ZZ
          * After that we sum them and normalise
          */
-        for (j = 0; (j < nf2); j++)
+        for (j = 0; (j < nframes); j++)
         {
             csum[j] = 0.0;
         }
         for (m = 0; (m < DIM); m++)
         {
             /* Copy the vector data in a linear array */
-            for (j = 0; (j < nf2); j++)
+            for (j = 0; (j < nframes); j++)
             {
                 ctmp[j] = c1[DIM*j+m];
             }
-            low_do_four_core(nfour, nf2, ctmp, cfour, enNorm);
-            for (j = 0; (j < nf2); j++)
+            low_do_four_core(nframes, ctmp, cfour, enNorm);
+            for (j = 0; (j < nframes); j++)
             {
                 csum[j] += cfour[j];
             }
@@ -517,7 +523,7 @@ void do_four_core(unsigned long mode, int nfour, int nf2, int nframes,
     }
 
     sfree(cfour);
-    for (j = 0; (j < nf2); j++)
+    for (j = 0; (j < nframes); j++)
     {
         c1[j] = csum[j]/(real)(nframes-j);
     }
@@ -531,7 +537,7 @@ void low_do_autocorr(const char *fn, const gmx_output_env_t *oenv, const char *t
                      int eFitFn)
 {
     FILE       *fp, *gp = NULL;
-    int         i, nfour;
+    int         i;
     real       *csum;
     real       *ctmp, *fit;
     real        sum, Ct2av, Ctav;
@@ -576,30 +582,9 @@ void low_do_autocorr(const char *fn, const gmx_output_env_t *oenv, const char *t
                gmx::boolToString(bNormalize));
         printf("mode = %lu, dt = %g, nrestart = %d\n", mode, dt, nrestart);
     }
-    if (bFour)
-    {
-        /* For FTT corr., we need to pad the data with at least nframes zeros */
-        nfour = 2;
-        while (2*nframes > nfour)
-        {
-            nfour *= 2;
-        }
-        if (debug)
-        {
-            fprintf(debug, "Using FFT to calculate %s, #points for FFT = %d\n",
-                    title, nfour);
-        }
-
-        /* Allocate temp arrays */
-        snew(csum, nfour);
-        snew(ctmp, nfour);
-    }
-    else
-    {
-        nfour = 0; /* To keep the compiler happy */
-        snew(csum, nframes);
-        snew(ctmp, nframes);
-    }
+    /* Allocate temp arrays */
+    snew(csum, nframes);
+    snew(ctmp, nframes);
 
     /* Loop over items (e.g. molecules or dihedrals)
      * In this loop the actual correlation functions are computed, but without
@@ -615,7 +600,7 @@ void low_do_autocorr(const char *fn, const gmx_output_env_t *oenv, const char *t
 
         if (bFour)
         {
-            do_four_core(mode, nfour, nframes, nframes, c1[i], csum, ctmp);
+            do_four_core(mode, nframes, c1[i], csum, ctmp);
         }
         else
         {
index b05dd6619068df6a1a2a675d3ce3be052f21c772..e1df9220e967daace00571c18e9f290f1f028bc5 100644 (file)
 
 #include "manyautocorrelation.h"
 
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <cmath>
-
 #include <algorithm>
 
 #include "gromacs/fft/fft.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxomp.h"
-#include "gromacs/utility/smalloc.h"
 
-int many_auto_correl(int nfunc, int ndata, int nfft, real **c)
+int many_auto_correl(std::vector<std::vector<real> > *c)
 {
+    size_t nfunc = (*c).size();
+    if (nfunc == 0)
+    {
+        GMX_THROW(gmx::InconsistentInputError("Empty array of vectors supplied"));
+    }
+    size_t ndata = (*c)[0].size();
+    if (ndata == 0)
+    {
+        GMX_THROW(gmx::InconsistentInputError("Empty vector supplied"));
+    }
+#ifndef NDEBUG
+    for (size_t i = 1; i < nfunc; i++)
+    {
+        if ((*c)[i].size() != ndata)
+        {
+            char buf[256];
+            snprintf(buf, sizeof(buf), "Vectors of different lengths supplied (%d %d)",
+                     static_cast<int>((*c)[i].size()),
+                     static_cast<int>(ndata));
+            GMX_THROW(gmx::InconsistentInputError(buf));
+        }
+    }
+#endif
+    // Add buffer size to the arrays.
+    size_t nfft = (3*ndata/2) + 1;
+    // Pad arrays with zeros
+    for (auto &i : *c)
+    {
+        i.resize(nfft, 0);
+    }
     #pragma omp parallel
     {
         try
         {
-            typedef real complex[2];
-            int          i, j;
-            gmx_fft_t    fft1;
-            complex     *in, *out;
-            int          i0, i1;
-            int          nthreads, thread_id;
+            gmx_fft_t         fft1;
+            std::vector<real> in, out;
 
-            nthreads  = gmx_omp_get_max_threads();
-            thread_id = gmx_omp_get_thread_num();
-            if ((0 == thread_id))
-            {
-                // fprintf(stderr, "There are %d threads for correlation functions\n", nthreads);
-            }
-            i0 = thread_id*nfunc/nthreads;
-            i1 = std::min(nfunc, (thread_id+1)*nfunc/nthreads);
+            int               nthreads  = gmx_omp_get_max_threads();
+            int               thread_id = gmx_omp_get_thread_num();
+            int               i0        = (thread_id*nfunc)/nthreads;
+            int               i1        = std::min(nfunc, ((thread_id+1)*nfunc)/nthreads);
 
             gmx_fft_init_1d(&fft1, nfft, GMX_FFT_FLAG_CONSERVATIVE);
             /* Allocate temporary arrays */
-            snew(in, nfft);
-            snew(out, nfft);
-            for (i = i0; (i < i1); i++)
+            in.resize(2*nfft, 0);
+            out.resize(2*nfft, 0);
+            for (int i = i0; (i < i1); i++)
             {
-                for (j = 0; j < ndata; j++)
-                {
-                    in[j][0] = c[i][j];
-                    in[j][1] = 0;
-                }
-                for (; (j < nfft); j++)
+                for (size_t j = 0; j < ndata; j++)
                 {
-                    in[j][0] = in[j][1] = 0;
+                    in[2*j+0] = (*c)[i][j];
+                    in[2*j+1] = 0;
                 }
-
-                gmx_fft_1d(fft1, GMX_FFT_BACKWARD, (void *)in, (void *)out);
-                for (j = 0; j < nfft; j++)
+                gmx_fft_1d(fft1, GMX_FFT_BACKWARD, (void *)in.data(), (void *)out.data());
+                for (size_t j = 0; j < nfft; j++)
                 {
-                    in[j][0] = (out[j][0]*out[j][0] + out[j][1]*out[j][1])/nfft;
-                    in[j][1] = 0;
+                    in[2*j+0] = (out[2*j+0]*out[2*j+0] + out[2*j+1]*out[2*j+1])/nfft;
+                    in[2*j+1] = 0;
                 }
-                for (; (j < nfft); j++)
+                gmx_fft_1d(fft1, GMX_FFT_FORWARD, (void *)in.data(), (void *)out.data());
+                for (size_t j = 0; (j < nfft); j++)
                 {
-                    in[j][0] = in[j][1] = 0;
-                }
-
-                gmx_fft_1d(fft1, GMX_FFT_FORWARD, (void *)in, (void *)out);
-                for (j = 0; (j < nfft); j++)
-                {
-                    c[i][j] = out[j][0];
+                    (*c)[i][j] = out[2*j+0];
                 }
             }
             /* Free the memory */
             gmx_fft_destroy(fft1);
-            sfree(in);
-            sfree(out);
         }
         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
     }
-    // gmx_fft_cleanup();
+    for (auto &i : *c)
+    {
+        i.resize(ndata);
+    }
+
     return 0;
 }
index 160f2da71a2b1446104a3cd24cd6ade94f64a549..63409bcef5415e347d254611d3ed0b97ce2fbd5b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014, by the GROMACS development team, led by
+ * Copyright (c) 2014,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 #ifndef GMX_MANYAUTOCORRELATION_H
 #define GMX_MANYAUTOCORRELATION_H
 
+#include <vector>
+
 #include "gromacs/fft/fft.h"
 #include "gromacs/utility/real.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /*! \brief
  * Perform many autocorrelation calculations.
  *
  * This routine performs many autocorrelation function calculations using FFTs.
- * The GROMACS FFT library wrapper is employed. On return the c[] arrays contain
+ * The GROMACS FFT library wrapper is employed. On return the c vector contain
  * a symmetric function that is useful for further FFT:ing, for instance in order to
  * compute spectra.
  *
+ * The vectors c[i] should all have the same length, but this is not checked for.
+ *
+ * The c arrays will be extend and filled with zero beyond ndata before
+ * computing the correlation.
+ *
  * The functions uses OpenMP parallellization.
  *
- * \param[in] nfunc   Number of data functions to autocorrelate
- * \param[in] ndata   Number of valid data points in the data
- * \param[in] nfft    Length of the data arrays, this should at least be 50% larger than ndata. The c arrays will filled with zero beyond ndata before computing the correlation.
- * \param[inout] c    Data array of size nfunc x nfft, will also be used for output
+ * \param[inout] c Data array
  * \return fft error code, or zero if everything went fine (see fft/fft.h)
+ * \throws gmx::InconsistentInputError if the input is inconsistent.
  */
-int many_auto_correl(int nfunc, int ndata, int nfft, real **c);
-
-#ifdef __cplusplus
-}
-#endif
+int many_auto_correl(std::vector<std::vector<real> > *c);
 
 #endif
index 5bb3ad4fef67348779e1d49ab93abe9bd3b6ad6a..1bcb355f5cab07323a4114ff9c84c9e1169bd1ea 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2014, by the GROMACS development team, led by
+# Copyright (c) 2014,2016, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -34,6 +34,7 @@
 
 gmx_add_unit_test(CorrelationsTest  correlations-test
   autocorr.cpp
+  manyautocorrelation.cpp
   correlationdataset.cpp
   expfit.cpp)
 
diff --git a/src/gromacs/correlationfunctions/tests/manyautocorrelation.cpp b/src/gromacs/correlationfunctions/tests/manyautocorrelation.cpp
new file mode 100644 (file)
index 0000000..92a8e85
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2014,2015,2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Implements low level test of manyautocorrelation routines
+ *
+ * \author David van der Spoel <david.vanderspoel@icm.uu.se>
+ * \ingroup module_correlationfunctions
+ */
+#include "gmxpre.h"
+
+#include "gromacs/correlationfunctions/manyautocorrelation.h"
+
+#include <cmath>
+
+#include <memory>
+
+#include <gtest/gtest.h>
+
+#include "gromacs/utility/exceptions.h"
+
+#include "testutils/testasserts.h"
+#include "testutils/testfilemanager.h"
+
+namespace gmx
+{
+namespace
+{
+
+class ManyAutocorrelationTest : public ::testing::Test
+{
+};
+
+TEST_F (ManyAutocorrelationTest, Empty)
+{
+    std::vector<std::vector<real> > c;
+    EXPECT_THROW_GMX(many_auto_correl(&c), gmx::InconsistentInputError);
+}
+
+#ifndef NDEBUG
+TEST_F (ManyAutocorrelationTest, DifferentLength)
+{
+    std::vector<std::vector<real> > c;
+    c.resize(3);
+    c[0].resize(10);
+    c[1].resize(10);
+    c[2].resize(8);
+    EXPECT_THROW_GMX(many_auto_correl(&c), gmx::InconsistentInputError);
+}
+#endif
+
+}
+
+}
index ac17ffb7dd0081b98ee7d34fc2bc7656ae063f56..93a685edce4cbf4c90620d432dc88786363d23d7 100644 (file)
@@ -70,6 +70,7 @@
 #include "gromacs/mdlib/gmx_omp_nthreads.h"
 #include "gromacs/mdlib/mdatoms.h"
 #include "gromacs/mdlib/mdrun.h"
+#include "gromacs/mdlib/mdsetup.h"
 #include "gromacs/mdlib/nb_verlet.h"
 #include "gromacs/mdlib/nbnxn_grid.h"
 #include "gromacs/mdlib/nsgrid.h"
@@ -91,6 +92,7 @@
 #include "gromacs/topology/block.h"
 #include "gromacs/topology/idef.h"
 #include "gromacs/topology/ifunc.h"
+#include "gromacs/topology/mtop_lookup.h"
 #include "gromacs/topology/mtop_util.h"
 #include "gromacs/topology/topology.h"
 #include "gromacs/utility/basedefinitions.h"
@@ -301,13 +303,8 @@ void dd_store_state(gmx_domdec_t *dd, t_state *state)
         gmx_incons("The state does not the domain decomposition state");
     }
 
-    state->ncg_gl = dd->ncg_home;
-    if (state->ncg_gl > state->cg_gl_nalloc)
-    {
-        state->cg_gl_nalloc = over_alloc_dd(state->ncg_gl);
-        srenew(state->cg_gl, state->cg_gl_nalloc);
-    }
-    for (i = 0; i < state->ncg_gl; i++)
+    state->cg_gl.resize(dd->ncg_home);
+    for (i = 0; i < dd->ncg_home; i++)
     {
         state->cg_gl[i] = dd->index_gl[i];
     }
@@ -364,6 +361,15 @@ void dd_get_ns_ranges(const gmx_domdec_t *dd, int icg,
     }
 }
 
+int dd_natoms_mdatoms(const gmx_domdec_t *dd)
+{
+    /* We currently set mdatoms entries for all atoms:
+     * local + non-local + communicated for vsite + constraints
+     */
+
+    return dd->comm->nat[ddnatNR - 1];
+}
+
 int dd_natoms_vsite(const gmx_domdec_t *dd)
 {
     return dd->comm->nat[ddnatVSITE];
@@ -1075,8 +1081,8 @@ static void dd_collect_cg(gmx_domdec_t *dd,
 
         cgs_gl = &dd->comm->cgs_gl;
 
-        ncg_home = state_local->ncg_gl;
-        cg       = state_local->cg_gl;
+        ncg_home = state_local->cg_gl.size();
+        cg       = state_local->cg_gl.data();
         nat_home = 0;
         for (i = 0; i < ncg_home; i++)
         {
@@ -1140,7 +1146,7 @@ static void dd_collect_cg(gmx_domdec_t *dd,
 }
 
 static void dd_collect_vec_sendrecv(gmx_domdec_t *dd,
-                                    rvec *lv, rvec *v)
+                                    const rvec *lv, rvec *v)
 {
     gmx_domdec_master_t *ma;
     int                  n, i, c, a, nalloc = 0;
@@ -1152,8 +1158,8 @@ static void dd_collect_vec_sendrecv(gmx_domdec_t *dd,
     if (!DDMASTER(dd))
     {
 #if GMX_MPI
-        MPI_Send(lv, dd->nat_home*sizeof(rvec), MPI_BYTE, DDMASTERRANK(dd),
-                 dd->rank, dd->mpi_comm_all);
+        MPI_Send(const_cast<void *>(static_cast<const void *>(lv)), dd->nat_home*sizeof(rvec), MPI_BYTE,
+                 DDMASTERRANK(dd), dd->rank, dd->mpi_comm_all);
 #endif
     }
     else
@@ -1217,7 +1223,7 @@ static void get_commbuffer_counts(gmx_domdec_t *dd,
 }
 
 static void dd_collect_vec_gatherv(gmx_domdec_t *dd,
-                                   rvec *lv, rvec *v)
+                                   const rvec *lv, rvec *v)
 {
     gmx_domdec_master_t *ma;
     int                 *rcounts = NULL, *disps = NULL;
@@ -1254,11 +1260,15 @@ static void dd_collect_vec_gatherv(gmx_domdec_t *dd,
     }
 }
 
-void dd_collect_vec(gmx_domdec_t *dd,
-                    t_state *state_local, rvec *lv, rvec *v)
+void dd_collect_vec(gmx_domdec_t           *dd,
+                    t_state                *state_local,
+                    const PaddedRVecVector *localVector,
+                    rvec                   *v)
 {
     dd_collect_cg(dd, state_local);
 
+    const rvec *lv = as_rvec_array(localVector->data());
+
     if (dd->nnodes <= GMX_DD_NNODES_SENDRECV)
     {
         dd_collect_vec_sendrecv(dd, lv, v);
@@ -1269,6 +1279,14 @@ void dd_collect_vec(gmx_domdec_t *dd,
     }
 }
 
+void dd_collect_vec(gmx_domdec_t           *dd,
+                    t_state                *state_local,
+                    const PaddedRVecVector *localVector,
+                    PaddedRVecVector       *vector)
+{
+    dd_collect_vec(dd, state_local, localVector, as_rvec_array(vector->data()));
+}
+
 
 void dd_collect_state(gmx_domdec_t *dd,
                       t_state *state_local, t_state *state)
@@ -1317,15 +1335,15 @@ void dd_collect_state(gmx_domdec_t *dd,
             switch (est)
             {
                 case estX:
-                    dd_collect_vec(dd, state_local, state_local->x, state->x);
+                    dd_collect_vec(dd, state_local, &state_local->x, &state->x);
                     break;
                 case estV:
-                    dd_collect_vec(dd, state_local, state_local->v, state->v);
+                    dd_collect_vec(dd, state_local, &state_local->v, &state->v);
                     break;
                 case est_SDX_NOTSUPPORTED:
                     break;
                 case estCGP:
-                    dd_collect_vec(dd, state_local, state_local->cg_p, state->cg_p);
+                    dd_collect_vec(dd, state_local, &state_local->cg_p, &state->cg_p);
                     break;
                 case estDISRE_INITF:
                 case estDISRE_RM3TAV:
@@ -1339,17 +1357,15 @@ void dd_collect_state(gmx_domdec_t *dd,
     }
 }
 
-static void dd_realloc_state(t_state *state, rvec **f, int nalloc)
+static void dd_resize_state(t_state *state, PaddedRVecVector *f, int natoms)
 {
     int est;
 
     if (debug)
     {
-        fprintf(debug, "Reallocating state: currently %d, required %d, allocating %d\n", state->nalloc, nalloc, over_alloc_dd(nalloc));
+        fprintf(debug, "Resizing state: currently %d, required %d\n", state->natoms, natoms);
     }
 
-    state->nalloc = over_alloc_dd(nalloc);
-
     for (est = 0; est < estNR; est++)
     {
         if (EST_DISTR(est) && (state->flags & (1<<est)))
@@ -1360,15 +1376,15 @@ static void dd_realloc_state(t_state *state, rvec **f, int nalloc)
             switch (est)
             {
                 case estX:
-                    srenew(state->x, state->nalloc + 1);
+                    state->x.resize(natoms + 1);
                     break;
                 case estV:
-                    srenew(state->v, state->nalloc + 1);
+                    state->v.resize(natoms + 1);
                     break;
                 case est_SDX_NOTSUPPORTED:
                     break;
                 case estCGP:
-                    srenew(state->cg_p, state->nalloc + 1);
+                    state->cg_p.resize(natoms + 1);
                     break;
                 case estDISRE_INITF:
                 case estDISRE_RM3TAV:
@@ -1377,39 +1393,41 @@ static void dd_realloc_state(t_state *state, rvec **f, int nalloc)
                     /* No reallocation required */
                     break;
                 default:
-                    gmx_incons("Unknown state entry encountered in dd_realloc_state");
+                    gmx_incons("Unknown state entry encountered in dd_resize_state");
             }
         }
     }
 
     if (f != NULL)
     {
-        srenew(*f, state->nalloc);
+        (*f).resize(natoms + 1);
     }
 }
 
-static void dd_check_alloc_ncg(t_forcerec *fr, t_state *state, rvec **f,
-                               int nalloc)
+static void dd_check_alloc_ncg(t_forcerec       *fr,
+                               t_state          *state,
+                               PaddedRVecVector *f,
+                               int               numChargeGroups)
 {
-    if (nalloc > fr->cg_nalloc)
+    if (numChargeGroups > fr->cg_nalloc)
     {
         if (debug)
         {
-            fprintf(debug, "Reallocating forcerec: currently %d, required %d, allocating %d\n", fr->cg_nalloc, nalloc, over_alloc_dd(nalloc));
+            fprintf(debug, "Reallocating forcerec: currently %d, required %d, allocating %d\n", fr->cg_nalloc, numChargeGroups, over_alloc_dd(numChargeGroups));
         }
-        fr->cg_nalloc = over_alloc_dd(nalloc);
+        fr->cg_nalloc = over_alloc_dd(numChargeGroups);
         srenew(fr->cginfo, fr->cg_nalloc);
         if (fr->cutoff_scheme == ecutsGROUP)
         {
             srenew(fr->cg_cm, fr->cg_nalloc);
         }
     }
-    if (fr->cutoff_scheme == ecutsVERLET && nalloc > state->nalloc)
+    if (fr->cutoff_scheme == ecutsVERLET)
     {
         /* We don't use charge groups, we use x in state to set up
          * the atom communication.
          */
-        dd_realloc_state(state, f, nalloc);
+        dd_resize_state(state, f, numChargeGroups);
     }
 }
 
@@ -1519,7 +1537,11 @@ static void dd_distribute_vec(gmx_domdec_t *dd, t_block *cgs, rvec *v, rvec *lv)
 
 static void dd_distribute_dfhist(gmx_domdec_t *dd, df_history_t *dfhist)
 {
-    int i;
+    if (dfhist == NULL)
+    {
+        return;
+    }
+
     dd_bcast(dd, sizeof(int), &dfhist->bEquil);
     dd_bcast(dd, sizeof(int), &dfhist->nlambda);
     dd_bcast(dd, sizeof(real), &dfhist->wl_delta);
@@ -1534,7 +1556,7 @@ static void dd_distribute_dfhist(gmx_domdec_t *dd, df_history_t *dfhist)
         dd_bcast(dd, sizeof(real)*nlam, dfhist->sum_minvar);
         dd_bcast(dd, sizeof(real)*nlam, dfhist->sum_variance);
 
-        for (i = 0; i < nlam; i++)
+        for (int i = 0; i < nlam; i++)
         {
             dd_bcast(dd, sizeof(real)*nlam, dfhist->accum_p[i]);
             dd_bcast(dd, sizeof(real)*nlam, dfhist->accum_m[i]);
@@ -1548,7 +1570,7 @@ static void dd_distribute_dfhist(gmx_domdec_t *dd, df_history_t *dfhist)
 
 static void dd_distribute_state(gmx_domdec_t *dd, t_block *cgs,
                                 t_state *state, t_state *state_local,
-                                rvec **f)
+                                PaddedRVecVector *f)
 {
     int  i, j, nh;
 
@@ -1568,7 +1590,10 @@ static void dd_distribute_state(gmx_domdec_t *dd, t_block *cgs,
         copy_mat(state->boxv, state_local->boxv);
         copy_mat(state->svir_prev, state_local->svir_prev);
         copy_mat(state->fvir_prev, state_local->fvir_prev);
-        copy_df_history(&state_local->dfhist, &state->dfhist);
+        if (state->dfhist != NULL)
+        {
+            copy_df_history(state_local->dfhist, state->dfhist);
+        }
         for (i = 0; i < state_local->ngtc; i++)
         {
             for (j = 0; j < nh; j++)
@@ -1587,7 +1612,7 @@ static void dd_distribute_state(gmx_domdec_t *dd, t_block *cgs,
             }
         }
     }
-    dd_bcast(dd, ((efptNR)*sizeof(real)), state_local->lambda);
+    dd_bcast(dd, ((efptNR)*sizeof(real)), state_local->lambda.data());
     dd_bcast(dd, sizeof(int), &state_local->fep_state);
     dd_bcast(dd, sizeof(real), &state_local->veta);
     dd_bcast(dd, sizeof(real), &state_local->vol0);
@@ -1596,19 +1621,17 @@ static void dd_distribute_state(gmx_domdec_t *dd, t_block *cgs,
     dd_bcast(dd, sizeof(state_local->boxv), state_local->boxv);
     dd_bcast(dd, sizeof(state_local->svir_prev), state_local->svir_prev);
     dd_bcast(dd, sizeof(state_local->fvir_prev), state_local->fvir_prev);
-    dd_bcast(dd, ((state_local->ngtc*nh)*sizeof(double)), state_local->nosehoover_xi);
-    dd_bcast(dd, ((state_local->ngtc*nh)*sizeof(double)), state_local->nosehoover_vxi);
-    dd_bcast(dd, state_local->ngtc*sizeof(double), state_local->therm_integral);
-    dd_bcast(dd, ((state_local->nnhpres*nh)*sizeof(double)), state_local->nhpres_xi);
-    dd_bcast(dd, ((state_local->nnhpres*nh)*sizeof(double)), state_local->nhpres_vxi);
+    dd_bcast(dd, ((state_local->ngtc*nh)*sizeof(double)), state_local->nosehoover_xi.data());
+    dd_bcast(dd, ((state_local->ngtc*nh)*sizeof(double)), state_local->nosehoover_vxi.data());
+    dd_bcast(dd, state_local->ngtc*sizeof(double), state_local->therm_integral.data());
+    dd_bcast(dd, ((state_local->nnhpres*nh)*sizeof(double)), state_local->nhpres_xi.data());
+    dd_bcast(dd, ((state_local->nnhpres*nh)*sizeof(double)), state_local->nhpres_vxi.data());
 
     /* communicate df_history -- required for restarting from checkpoint */
-    dd_distribute_dfhist(dd, &state_local->dfhist);
+    dd_distribute_dfhist(dd, state_local->dfhist);
+
+    dd_resize_state(state_local, f, dd->nat_home);
 
-    if (dd->nat_home > state_local->nalloc)
-    {
-        dd_realloc_state(state_local, f, dd->nat_home);
-    }
     for (i = 0; i < estNR; i++)
     {
         if (EST_DISTR(i) && (state_local->flags & (1<<i)))
@@ -1616,15 +1639,15 @@ static void dd_distribute_state(gmx_domdec_t *dd, t_block *cgs,
             switch (i)
             {
                 case estX:
-                    dd_distribute_vec(dd, cgs, state->x, state_local->x);
+                    dd_distribute_vec(dd, cgs, as_rvec_array(state->x.data()), as_rvec_array(state_local->x.data()));
                     break;
                 case estV:
-                    dd_distribute_vec(dd, cgs, state->v, state_local->v);
+                    dd_distribute_vec(dd, cgs, as_rvec_array(state->v.data()), as_rvec_array(state_local->v.data()));
                     break;
                 case est_SDX_NOTSUPPORTED:
                     break;
                 case estCGP:
-                    dd_distribute_vec(dd, cgs, state->cg_p, state_local->cg_p);
+                    dd_distribute_vec(dd, cgs, as_rvec_array(state->cg_p.data()), as_rvec_array(state_local->cg_p.data()));
                     break;
                 case estDISRE_INITF:
                 case estDISRE_RM3TAV:
@@ -1749,7 +1772,7 @@ void write_dd_pdb(const char *fn, gmx_int64_t step, const char *title,
     char          fname[STRLEN], buf[22];
     FILE         *out;
     int           i, ii, resnr, c;
-    char         *atomname, *resname;
+    const char   *atomname, *resname;
     real          b;
     gmx_domdec_t *dd;
 
@@ -1765,10 +1788,11 @@ void write_dd_pdb(const char *fn, gmx_int64_t step, const char *title,
 
     fprintf(out, "TITLE     %s\n", title);
     gmx_write_pdb_box(out, dd->bScrewPBC ? epbcSCREW : epbcXYZ, box);
+    int molb = 0;
     for (i = 0; i < natoms; i++)
     {
         ii = dd->gatindex[i];
-        gmx_mtop_atominfo_global(mtop, ii, &atomname, &resnr, &resname);
+        mtopGetAtomAndResidueName(mtop, ii, &molb, &atomname, &resnr, &resname, nullptr);
         if (i < dd->comm->nat[ddnatZONE])
         {
             c = 0;
@@ -2151,25 +2175,26 @@ static void set_zones_ncg_home(gmx_domdec_t *dd)
 }
 
 static void rebuild_cgindex(gmx_domdec_t *dd,
-                            const int *gcgs_index, t_state *state)
+                            const int *gcgs_index, const t_state *state)
 {
-    int nat, i, *ind, *dd_cg_gl, *cgindex, cg_gl;
+    int * gmx_restrict dd_cg_gl = dd->index_gl;
+    int * gmx_restrict cgindex  = dd->cgindex;
+    int                nat      = 0;
 
-    ind        = state->cg_gl;
-    dd_cg_gl   = dd->index_gl;
-    cgindex    = dd->cgindex;
-    nat        = 0;
+    /* Copy back the global charge group indices from state
+     * and rebuild the local charge group to atom index.
+     */
     cgindex[0] = nat;
-    for (i = 0; i < state->ncg_gl; i++)
+    for (unsigned int i = 0; i < state->cg_gl.size(); i++)
     {
         cgindex[i]  = nat;
-        cg_gl       = ind[i];
+        int cg_gl   = state->cg_gl[i];
         dd_cg_gl[i] = cg_gl;
         nat        += gcgs_index[cg_gl+1] - gcgs_index[cg_gl];
     }
-    cgindex[i] = nat;
+    cgindex[state->cg_gl.size()] = nat;
 
-    dd->ncg_home = state->ncg_gl;
+    dd->ncg_home = state->cg_gl.size();
     dd->nat_home = nat;
 
     set_zones_ncg_home(dd);
@@ -4232,7 +4257,7 @@ static void calc_cg_move(FILE *fplog, gmx_int64_t step,
                     if (pos_d >= limit1[d])
                     {
                         cg_move_error(fplog, dd, step, cg, d, 1,
-                                      cg_cm != state->x, limitd[d],
+                                      cg_cm != as_rvec_array(state->x.data()), limitd[d],
                                       cg_cm[cg], cm_new, pos_d);
                     }
                     dev[d] = 1;
@@ -4259,7 +4284,7 @@ static void calc_cg_move(FILE *fplog, gmx_int64_t step,
                     if (pos_d < limit0[d])
                     {
                         cg_move_error(fplog, dd, step, cg, d, -1,
-                                      cg_cm != state->x, limitd[d],
+                                      cg_cm != as_rvec_array(state->x.data()), limitd[d],
                                       cg_cm[cg], cm_new, pos_d);
                     }
                     dev[d] = -1;
@@ -4343,7 +4368,7 @@ static void calc_cg_move(FILE *fplog, gmx_int64_t step,
 
 static void dd_redistribute_cg(FILE *fplog, gmx_int64_t step,
                                gmx_domdec_t *dd, ivec tric_dir,
-                               t_state *state, rvec **f,
+                               t_state *state, PaddedRVecVector *f,
                                t_forcerec *fr,
                                gmx_bool bCompact,
                                t_nrnb *nrnb,
@@ -4472,7 +4497,7 @@ static void dd_redistribute_cg(FILE *fplog, gmx_int64_t step,
                          cgindex,
                          ( thread   *dd->ncg_home)/nthread,
                          ((thread+1)*dd->ncg_home)/nthread,
-                         fr->cutoff_scheme == ecutsGROUP ? cg_cm : state->x,
+                         fr->cutoff_scheme == ecutsGROUP ? cg_cm : as_rvec_array(state->x.data()),
                          move);
         }
         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
@@ -4551,7 +4576,7 @@ static void dd_redistribute_cg(FILE *fplog, gmx_int64_t step,
              */
             home_pos_cg =
                 compact_and_copy_vec_cg(dd->ncg_home, move, cgindex,
-                                        nvec, state->x, comm, FALSE);
+                                        nvec, as_rvec_array(state->x.data()), comm, FALSE);
             if (bCompact)
             {
                 home_pos_cg -= *ncg_moved;
@@ -4565,16 +4590,19 @@ static void dd_redistribute_cg(FILE *fplog, gmx_int64_t step,
     vec         = 0;
     home_pos_at =
         compact_and_copy_vec_at(dd->ncg_home, move, cgindex,
-                                nvec, vec++, state->x, comm, bCompact);
+                                nvec, vec++, as_rvec_array(state->x.data()),
+                                comm, bCompact);
     if (bV)
     {
         compact_and_copy_vec_at(dd->ncg_home, move, cgindex,
-                                nvec, vec++, state->v, comm, bCompact);
+                                nvec, vec++, as_rvec_array(state->v.data()),
+                                comm, bCompact);
     }
     if (bCGP)
     {
         compact_and_copy_vec_at(dd->ncg_home, move, cgindex,
-                                nvec, vec++, state->cg_p, comm, bCompact);
+                                nvec, vec++, as_rvec_array(state->cg_p.data()),
+                                comm, bCompact);
     }
 
     if (bCompact)
@@ -4650,6 +4678,13 @@ static void dd_redistribute_cg(FILE *fplog, gmx_int64_t step,
             nvr      += i;
         }
 
+        dd_check_alloc_ncg(fr, state, f, home_pos_cg + ncg_recv);
+        if (fr->cutoff_scheme == ecutsGROUP)
+        {
+            /* Here we resize to more than necessary and shrink later */
+            dd_resize_state(state, f, home_pos_at + ncg_recv*MAX_CGCGSIZE);
+        }
+
         /* Process the received charge groups */
         buf_pos = 0;
         for (cg = 0; cg < ncg_recv; cg++)
@@ -4762,7 +4797,6 @@ static void dd_redistribute_cg(FILE *fplog, gmx_int64_t step,
                 dd->index_gl[home_pos_cg]  = comm->buf_int[cg*DD_CGIBS];
                 dd->cgindex[home_pos_cg+1] = dd->cgindex[home_pos_cg] + nrcg;
                 /* Copy the state from the buffer */
-                dd_check_alloc_ncg(fr, state, f, home_pos_cg+1);
                 if (fr->cutoff_scheme == ecutsGROUP)
                 {
                     cg_cm = fr->cg_cm;
@@ -4778,10 +4812,6 @@ static void dd_redistribute_cg(FILE *fplog, gmx_int64_t step,
                     comm->bLocalCG[dd->index_gl[home_pos_cg]] = TRUE;
                 }
 
-                if (home_pos_at+nrcg > state->nalloc)
-                {
-                    dd_realloc_state(state, f, home_pos_at+nrcg);
-                }
                 for (i = 0; i < nrcg; i++)
                 {
                     copy_rvec(comm->vbuf.v[buf_pos++],
@@ -4850,6 +4880,12 @@ static void dd_redistribute_cg(FILE *fplog, gmx_int64_t step,
     dd->ncg_home = home_pos_cg;
     dd->nat_home = home_pos_at;
 
+    if (fr->cutoff_scheme == ecutsGROUP && !bCompact)
+    {
+        /* We overallocated before, we need to set the right size here */
+        dd_resize_state(state, f, dd->nat_home);
+    }
+
     if (debug)
     {
         fprintf(debug,
@@ -7252,7 +7288,7 @@ static gmx_bool test_dd_cutoff(t_commrec *cr,
     dd = cr->dd;
 
     set_ddbox(dd, FALSE, cr, ir, state->box,
-              TRUE, &dd->comm->cgs_gl, state->x, &ddbox);
+              TRUE, &dd->comm->cgs_gl, as_rvec_array(state->x.data()), &ddbox);
 
     LocallyLimited = 0;
 
@@ -7931,7 +7967,8 @@ get_zone_pulse_cgs(gmx_domdec_t *dd,
 
 static void setup_dd_communication(gmx_domdec_t *dd,
                                    matrix box, gmx_ddbox_t *ddbox,
-                                   t_forcerec *fr, t_state *state, rvec **f)
+                                   t_forcerec *fr,
+                                   t_state *state, PaddedRVecVector *f)
 {
     int                    dim_ind, dim, dim0, dim1, dim2, dimd, p, nat_tot;
     int                    nzone, nzone_send, zone, zonei, cg0, cg1;
@@ -7978,7 +8015,7 @@ static void setup_dd_communication(gmx_domdec_t *dd,
             cg_cm = fr->cg_cm;
             break;
         case ecutsVERLET:
-            cg_cm = state->x;
+            cg_cm = as_rvec_array(state->x.data());
             break;
         default:
             gmx_incons("unimplemented");
@@ -8316,7 +8353,7 @@ static void setup_dd_communication(gmx_domdec_t *dd,
             }
             else
             {
-                cg_cm = state->x;
+                cg_cm = as_rvec_array(state->x.data());
             }
             /* Communicate cg_cm */
             if (cd->bInPlace)
@@ -8958,15 +8995,15 @@ static void dd_sort_state(gmx_domdec_t *dd, rvec *cgcm, t_forcerec *fr, t_state
             switch (i)
             {
                 case estX:
-                    order_vec_atom(dd->ncg_home, cgindex, cgsort, state->x, vbuf);
+                    order_vec_atom(dd->ncg_home, cgindex, cgsort, as_rvec_array(state->x.data()), vbuf);
                     break;
                 case estV:
-                    order_vec_atom(dd->ncg_home, cgindex, cgsort, state->v, vbuf);
+                    order_vec_atom(dd->ncg_home, cgindex, cgsort, as_rvec_array(state->v.data()), vbuf);
                     break;
                 case est_SDX_NOTSUPPORTED:
                     break;
                 case estCGP:
-                    order_vec_atom(dd->ncg_home, cgindex, cgsort, state->cg_p, vbuf);
+                    order_vec_atom(dd->ncg_home, cgindex, cgsort, as_rvec_array(state->cg_p.data()), vbuf);
                     break;
                 case estLD_RNG:
                 case estLD_RNGI:
@@ -9140,7 +9177,7 @@ void dd_partition_system(FILE                *fplog,
                          const gmx_mtop_t    *top_global,
                          const t_inputrec    *ir,
                          t_state             *state_local,
-                         rvec               **f,
+                         PaddedRVecVector    *f,
                          t_mdatoms           *mdatoms,
                          gmx_localtop_t      *top_local,
                          t_forcerec          *fr,
@@ -9370,10 +9407,10 @@ void dd_partition_system(FILE                *fplog,
         ncgindex_set = 0;
 
         set_ddbox(dd, bMasterState, cr, ir, state_global->box,
-                  TRUE, cgs_gl, state_global->x, &ddbox);
+                  TRUE, cgs_gl, as_rvec_array(state_global->x.data()), &ddbox);
 
         get_cg_distribution(fplog, dd, cgs_gl,
-                            state_global->box, &ddbox, state_global->x);
+                            state_global->box, &ddbox, as_rvec_array(state_global->x.data()));
 
         dd_distribute_state(dd, cgs_gl,
                             state_global, state_local, f);
@@ -9386,7 +9423,7 @@ void dd_partition_system(FILE                *fplog,
         if (fr->cutoff_scheme == ecutsGROUP)
         {
             calc_cgcm(fplog, 0, dd->ncg_home,
-                      &top_local->cgs, state_local->x, fr->cg_cm);
+                      &top_local->cgs, as_rvec_array(state_local->x.data()), fr->cg_cm);
         }
 
         inc_nrnb(nrnb, eNR_CGCM, dd->nat_home);
@@ -9417,7 +9454,7 @@ void dd_partition_system(FILE                *fplog,
         {
             /* Redetermine the cg COMs */
             calc_cgcm(fplog, 0, dd->ncg_home,
-                      &top_local->cgs, state_local->x, fr->cg_cm);
+                      &top_local->cgs, as_rvec_array(state_local->x.data()), fr->cg_cm);
         }
 
         inc_nrnb(nrnb, eNR_CGCM, dd->nat_home);
@@ -9425,7 +9462,7 @@ void dd_partition_system(FILE                *fplog,
         dd_set_cginfo(dd->index_gl, 0, dd->ncg_home, fr, comm->bLocalCG);
 
         set_ddbox(dd, bMasterState, cr, ir, state_local->box,
-                  TRUE, &top_local->cgs, state_local->x, &ddbox);
+                  TRUE, &top_local->cgs, as_rvec_array(state_local->x.data()), &ddbox);
 
         bRedist = dlbIsOn(comm);
     }
@@ -9444,7 +9481,7 @@ void dd_partition_system(FILE                *fplog,
             copy_rvec(comm->box_size, ddbox.box_size);
         }
         set_ddbox(dd, bMasterState, cr, ir, state_local->box,
-                  bNStGlobalComm, &top_local->cgs, state_local->x, &ddbox);
+                  bNStGlobalComm, &top_local->cgs, as_rvec_array(state_local->x.data()), &ddbox);
 
         bBoxChanged = TRUE;
         bRedist     = TRUE;
@@ -9533,7 +9570,7 @@ void dd_partition_system(FILE                *fplog,
                                   0, dd->ncg_home,
                                   comm->zones.dens_zone0,
                                   fr->cginfo,
-                                  state_local->x,
+                                  as_rvec_array(state_local->x.data()),
                                   ncg_moved, bRedist ? comm->moved : NULL,
                                   fr->nbv->grp[eintLocal].kernel_type,
                                   fr->nbv->grp[eintLocal].nbat);
@@ -9569,6 +9606,10 @@ void dd_partition_system(FILE                *fplog,
         }
         dd_sort_state(dd, fr->cg_cm, fr, state_local,
                       bResortAll ? -1 : ncg_home_old);
+
+        /* After sorting and compacting we set the correct size */
+        dd_resize_state(state_local, f, dd->nat_home);
+
         /* Rebuild all the indices */
         ga2la_clear(dd->ga2la);
         ncgindex_set = 0;
@@ -9597,7 +9638,7 @@ void dd_partition_system(FILE                *fplog,
 
     /*
        write_dd_pdb("dd_home",step,"dump",top_global,cr,
-                 -1,state_local->x,state_local->box);
+                 -1,as_rvec_array(state_local->x.data()),state_local->box);
      */
 
     wallcycle_sub_start(wcycle, ewcsDD_MAKETOP);
@@ -9610,7 +9651,7 @@ void dd_partition_system(FILE                *fplog,
     dd_make_local_top(dd, &comm->zones, dd->npbcdim, state_local->box,
                       comm->cellsize_min, np,
                       fr,
-                      fr->cutoff_scheme == ecutsGROUP ? fr->cg_cm : state_local->x,
+                      fr->cutoff_scheme == ecutsGROUP ? fr->cg_cm : as_rvec_array(state_local->x.data()),
                       vsite, top_global, top_local);
 
     wallcycle_sub_stop(wcycle, ewcsDD_MAKETOP);
@@ -9652,10 +9693,8 @@ void dd_partition_system(FILE                *fplog,
      * or constraint communication.
      */
     state_local->natoms = comm->nat[ddnatNR-1];
-    if (state_local->natoms > state_local->nalloc)
-    {
-        dd_realloc_state(state_local, f, state_local->natoms);
-    }
+
+    dd_resize_state(state_local, f, state_local->natoms);
 
     if (fr->bF_NoVirSum)
     {
@@ -9689,31 +9728,15 @@ void dd_partition_system(FILE                *fplog,
     forcerec_set_ranges(fr, dd->ncg_home, dd->ncg_tot,
                         dd->nat_tot, comm->nat[ddnatCON], nat_f_novirsum);
 
-    /* We make the all mdatoms up to nat_tot_con.
-     * We could save some work by only setting invmass
-     * between nat_tot and nat_tot_con.
-     */
-    /* This call also sets the new number of home particles to dd->nat_home */
-    atoms2md(top_global, ir,
-             comm->nat[ddnatCON], dd->gatindex, dd->nat_home, mdatoms);
-
-    /* Now we have the charges we can sort the FE interactions */
-    dd_sort_local_top(dd, mdatoms, top_local);
-
-    if (vsite != NULL)
-    {
-        /* Now we have updated mdatoms, we can do the last vsite bookkeeping */
-        split_vsites_over_threads(top_local->idef.il, top_local->idef.iparams,
-                                  mdatoms, FALSE, vsite);
-    }
+    /* Update atom data for mdatoms and several algorithms */
+    mdAlgorithmsSetupAtomData(cr, ir, top_global, top_local, fr,
+                              NULL, mdatoms, vsite, NULL);
 
     if (ir->implicit_solvent)
     {
         make_local_gb(cr, fr->born, ir->gb_algorithm);
     }
 
-    setup_bonded_threading(fr, &top_local->idef);
-
     if (!(cr->duty & DUTY_PME))
     {
         /* Send the charges and/or c6/sigmas to our PME only node */
@@ -9761,15 +9784,15 @@ void dd_partition_system(FILE                *fplog,
      * the last vsite construction, we need to communicate the constructing
      * atom coordinates again (for spreading the forces this MD step).
      */
-    dd_move_x_vsites(dd, state_local->box, state_local->x);
+    dd_move_x_vsites(dd, state_local->box, as_rvec_array(state_local->x.data()));
 
     wallcycle_sub_stop(wcycle, ewcsDD_TOPOTHER);
 
     if (comm->nstDDDump > 0 && step % comm->nstDDDump == 0)
     {
-        dd_move_x(dd, state_local->box, state_local->x);
+        dd_move_x(dd, state_local->box, as_rvec_array(state_local->x.data()));
         write_dd_pdb("dd_dump", step, "dump", top_global, cr,
-                     -1, state_local->x, state_local->box);
+                     -1, as_rvec_array(state_local->x.data()), state_local->box);
     }
 
     /* Store the partitioning step */
index a2d772a2214273c9bf43f7c2d7c15f1d0d0f7e01..7934b5bdc008768e34c13fe5c867955ab46d4e09 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2005,2006,2007,2008,2009,2010,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2005,2006,2007,2008,2009,2010,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -81,10 +81,6 @@ struct gmx_domdec_zones_t;
 struct t_commrec;
 struct t_inputrec;
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /*! \brief Returns the global topology atom number belonging to local atom index i.
  *
  * This function is intended for writing ASCII output
@@ -109,6 +105,9 @@ struct gmx_domdec_zones_t *domdec_zones(struct gmx_domdec_t *dd);
 void dd_get_ns_ranges(const gmx_domdec_t *dd, int icg,
                       int *jcg0, int *jcg1, ivec shift0, ivec shift1);
 
+/*! \brief Returns the atom range in the local state for atoms that need to be present in mdatoms */
+int dd_natoms_mdatoms(const gmx_domdec_t *dd);
+
 /*! \brief Returns the atom range in the local state for atoms involved in virtual sites */
 int dd_natoms_vsite(const gmx_domdec_t *dd);
 
@@ -208,7 +207,11 @@ void dd_setup_dlb_resource_sharing(struct t_commrec           *cr,
 
 /*! \brief Collects local rvec arrays \p lv to \p v on the master rank */
 void dd_collect_vec(struct gmx_domdec_t *dd,
-                    t_state *state_local, rvec *lv, rvec *v);
+                    t_state *state_local, const PaddedRVecVector *lv, rvec *v);
+
+/*! \brief Collects local rvec arrays \p lv to \p v on the master rank */
+void dd_collect_vec(struct gmx_domdec_t *dd,
+                    t_state *state_local, const PaddedRVecVector *lv, PaddedRVecVector *v);
 
 /*! \brief Collects the local state \p state_local to \p state on the master rank */
 void dd_collect_state(struct gmx_domdec_t *dd,
@@ -266,7 +269,7 @@ void dd_partition_system(FILE                *fplog,
                          const gmx_mtop_t    *top_global,
                          const t_inputrec    *ir,
                          t_state             *state_local,
-                         rvec               **f,
+                         PaddedRVecVector    *f,
                          t_mdatoms           *mdatoms,
                          gmx_localtop_t      *top_local,
                          t_forcerec          *fr,
@@ -399,8 +402,4 @@ void set_ddbox_cr(t_commrec *cr, const ivec *dd_nc,
                   const t_block *cgs, const rvec *x,
                   gmx_ddbox_t *ddbox);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif
index 5cece422a6e8e294fee875c2480bbcadc6b158a1..91565d67117875cf2991b7fc20432ed0c4826863 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2006,2007,2008,2009,2010,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2006,2007,2008,2009,2010,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -58,7 +58,7 @@
 #include "gromacs/mdlib/gmx_omp_nthreads.h"
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/pbcutil/ishift.h"
-#include "gromacs/topology/mtop_util.h"
+#include "gromacs/topology/mtop_lookup.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxassert.h"
@@ -242,51 +242,37 @@ static void atoms_to_settles(gmx_domdec_t *dd,
                              t_ilist *ils_local,
                              ind_req_t *ireq)
 {
-    gmx_ga2la_t            *ga2la;
-    gmx_mtop_atomlookup_t   alook;
-    int                     settle;
-    int                     nral, sa;
-    int                     cg, a, a_gl, a_glsa, a_gls[3], a_locs[3];
-    int                     mb, molnr, a_mol, offset;
-    const gmx_molblock_t   *molb;
-    const t_iatom          *ia1;
-    gmx_bool                a_home[3];
-    int                     nlocal;
-    gmx_bool                bAssign;
+    gmx_ga2la_t *ga2la = dd->ga2la;
+    int          nral  = NRAL(F_SETTLE);
 
-    ga2la  = dd->ga2la;
-
-    alook = gmx_mtop_atomlookup_settle_init(mtop);
-
-    nral = NRAL(F_SETTLE);
-
-    for (cg = cg_start; cg < cg_end; cg++)
+    int          mb    = 0;
+    for (int cg = cg_start; cg < cg_end; cg++)
     {
         if (GET_CGINFO_SETTLE(cginfo[cg]))
         {
-            for (a = dd->cgindex[cg]; a < dd->cgindex[cg+1]; a++)
+            for (int a = dd->cgindex[cg]; a < dd->cgindex[cg+1]; a++)
             {
-                a_gl = dd->gatindex[a];
-
-                gmx_mtop_atomnr_to_molblock_ind(alook, a_gl, &mb, &molnr, &a_mol);
-                molb = &mtop->molblock[mb];
+                int a_gl = dd->gatindex[a];
+                int a_mol;
+                mtopGetMolblockIndex(mtop, a_gl, &mb, NULL, &a_mol);
 
-                settle = at2settle_mt[molb->type][a_mol];
+                const gmx_molblock_t *molb   = &mtop->molblock[mb];
+                int                   settle = at2settle_mt[molb->type][a_mol];
 
                 if (settle >= 0)
                 {
-                    offset = a_gl - a_mol;
+                    int      offset  = a_gl - a_mol;
 
-                    ia1 = mtop->moltype[molb->type].ilist[F_SETTLE].iatoms;
+                    t_iatom *ia1     = mtop->moltype[molb->type].ilist[F_SETTLE].iatoms;
 
-                    bAssign = FALSE;
-                    nlocal  = 0;
-                    for (sa = 0; sa < nral; sa++)
+                    int      a_gls[3], a_locs[3];
+                    gmx_bool bAssign = FALSE;
+                    int      nlocal  = 0;
+                    for (int sa = 0; sa < nral; sa++)
                     {
-                        a_glsa     = offset + ia1[settle*(1+nral)+1+sa];
+                        int a_glsa = offset + ia1[settle*(1+nral)+1+sa];
                         a_gls[sa]  = a_glsa;
-                        a_home[sa] = ga2la_get_home(ga2la, a_glsa, &a_locs[sa]);
-                        if (a_home[sa])
+                        if (ga2la_get_home(ga2la, a_glsa, &a_locs[sa]))
                         {
                             if (nlocal == 0 && a_gl == a_glsa)
                             {
@@ -306,7 +292,7 @@ static void atoms_to_settles(gmx_domdec_t *dd,
 
                         ils_local->iatoms[ils_local->nr++] = ia1[settle*4];
 
-                        for (sa = 0; sa < nral; sa++)
+                        for (int sa = 0; sa < nral; sa++)
                         {
                             if (ga2la_get_home(ga2la, a_gls[sa], &a_locs[sa]))
                             {
@@ -332,8 +318,6 @@ static void atoms_to_settles(gmx_domdec_t *dd,
             }
         }
     }
-
-    gmx_mtop_atomlookup_destroy(alook);
 }
 
 /*! \brief Looks up constraint for the local atoms */
@@ -345,33 +329,28 @@ static void atoms_to_constraints(gmx_domdec_t *dd,
                                  ind_req_t *ireq)
 {
     const t_blocka             *at2con;
-    gmx_ga2la_t                *ga2la;
-    gmx_mtop_atomlookup_t       alook;
     int                         ncon1;
-    gmx_molblock_t             *molb;
     t_iatom                    *ia1, *ia2, *iap;
-    int                         nhome, cg, a, a_gl, a_mol, a_loc, b_lo, offset, mb, molnr, b_mol, i, con, con_offset;
-    gmx_domdec_constraints_t   *dc;
-    gmx_domdec_specat_comm_t   *dcc;
+    int                         a_loc, b_lo, offset, b_mol, i, con, con_offset;
 
-    dc  = dd->constraints;
-    dcc = dd->constraint_comm;
+    gmx_domdec_constraints_t   *dc     = dd->constraints;
+    gmx_domdec_specat_comm_t   *dcc    = dd->constraint_comm;
 
-    ga2la  = dd->ga2la;
+    gmx_ga2la_t                *ga2la  = dd->ga2la;
 
-    alook = gmx_mtop_atomlookup_init(mtop);
-
-    nhome = 0;
-    for (cg = 0; cg < dd->ncg_home; cg++)
+    int mb    = 0;
+    int nhome = 0;
+    for (int cg = 0; cg < dd->ncg_home; cg++)
     {
         if (GET_CGINFO_CONSTR(cginfo[cg]))
         {
-            for (a = dd->cgindex[cg]; a < dd->cgindex[cg+1]; a++)
+            for (int a = dd->cgindex[cg]; a < dd->cgindex[cg+1]; a++)
             {
-                a_gl = dd->gatindex[a];
+                int a_gl = dd->gatindex[a];
+                int molnr, a_mol;
+                mtopGetMolblockIndex(mtop, a_gl, &mb, &molnr, &a_mol);
 
-                gmx_mtop_atomnr_to_molblock_ind(alook, a_gl, &mb, &molnr, &a_mol);
-                molb = &mtop->molblock[mb];
+                const gmx_molblock_t *molb = &mtop->molblock[mb];
 
                 ncon1 = mtop->moltype[molb->type].ilist[F_CONSTR].nr/NRAL(F_SETTLE);
 
@@ -443,8 +422,6 @@ static void atoms_to_constraints(gmx_domdec_t *dd,
         }
     }
 
-    gmx_mtop_atomlookup_destroy(alook);
-
     if (debug)
     {
         fprintf(debug,
index 907e60c5f947398ab2f4d7cd8fc27f3eb653642a..452c0abaed9d24c1ade4f299736acbd6ab6d257d 100644 (file)
@@ -223,26 +223,13 @@ void dd_sendrecv2_rvec(const struct gmx_domdec_t gmx_unused *dd,
 #endif
 }
 
-/* IBM's BlueGene(/L) MPI_Bcast dereferences the data pointer
- * even when 0 == nbytes, so we protect calls to it on BlueGene.
- * Fortunately dd_bcast() and dd_bcastc() are only
- * called during DD setup and partition.
- */
-
 void dd_bcast(gmx_domdec_t gmx_unused *dd, int gmx_unused nbytes, void gmx_unused *data)
 {
 #if GMX_MPI
     if (dd->nnodes > 1)
     {
-#ifdef GMX_BLUEGENE
-        if (nbytes > 0)
-        {
-#endif
         MPI_Bcast(data, nbytes, MPI_BYTE,
                   DDMASTERRANK(dd), dd->mpi_comm_all);
-#ifdef GMX_BLUEGENE
-    }
-#endif
     }
 #endif
 }
@@ -256,25 +243,19 @@ void dd_bcastc(gmx_domdec_t *dd, int nbytes, void *src, void *dest)
 #if GMX_MPI
     if (dd->nnodes > 1)
     {
-#ifdef GMX_BLUEGENE
-        if (nbytes > 0)
-        {
-#endif
         MPI_Bcast(dest, nbytes, MPI_BYTE,
                   DDMASTERRANK(dd), dd->mpi_comm_all);
-#ifdef GMX_BLUEGENE
-    }
-#endif
     }
 #endif
 }
 
-void dd_scatter(gmx_domdec_t gmx_unused *dd, int gmx_unused nbytes, void gmx_unused *src, void *dest)
+void dd_scatter(gmx_domdec_t gmx_unused *dd, int gmx_unused nbytes, const void gmx_unused *src, void *dest)
 {
 #if GMX_MPI
     if (dd->nnodes > 1)
     {
-        MPI_Scatter(src, nbytes, MPI_BYTE,
+        /* Some MPI implementions don't specify const */
+        MPI_Scatter(const_cast<void *>(src), nbytes, MPI_BYTE,
                     dest, nbytes, MPI_BYTE,
                     DDMASTERRANK(dd), dd->mpi_comm_all);
     }
@@ -289,17 +270,18 @@ void dd_scatter(gmx_domdec_t gmx_unused *dd, int gmx_unused nbytes, void gmx_unu
     }
 }
 
-void dd_gather(gmx_domdec_t gmx_unused *dd, int gmx_unused nbytes, void gmx_unused *src, void gmx_unused *dest)
+void dd_gather(gmx_domdec_t gmx_unused *dd, int gmx_unused nbytes, const void gmx_unused *src, void gmx_unused *dest)
 {
 #if GMX_MPI
-    MPI_Gather(src, nbytes, MPI_BYTE,
+    /* Some MPI implementions don't specify const */
+    MPI_Gather(const_cast<void *>(src), nbytes, MPI_BYTE,
                dest, nbytes, MPI_BYTE,
                DDMASTERRANK(dd), dd->mpi_comm_all);
 #endif
 }
 
 void dd_scatterv(gmx_domdec_t gmx_unused *dd,
-                 int gmx_unused *scounts, int gmx_unused *disps, void *sbuf,
+                 int gmx_unused *scounts, int gmx_unused *disps, const void *sbuf,
                  int rcount, void *rbuf)
 {
 #if GMX_MPI
@@ -312,7 +294,8 @@ void dd_scatterv(gmx_domdec_t gmx_unused *dd,
             /* MPI does not allow NULL pointers */
             rbuf = &dum;
         }
-        MPI_Scatterv(sbuf, scounts, disps, MPI_BYTE,
+        /* Some MPI implementions don't specify const */
+        MPI_Scatterv(const_cast<void *>(sbuf), scounts, disps, MPI_BYTE,
                      rbuf, rcount, MPI_BYTE,
                      DDMASTERRANK(dd), dd->mpi_comm_all);
     }
@@ -328,7 +311,7 @@ void dd_scatterv(gmx_domdec_t gmx_unused *dd,
 }
 
 void dd_gatherv(gmx_domdec_t gmx_unused *dd,
-                int gmx_unused scount, void gmx_unused *sbuf,
+                int gmx_unused scount, const void gmx_unused *sbuf,
                 int gmx_unused *rcounts, int gmx_unused *disps, void gmx_unused *rbuf)
 {
 #if GMX_MPI
@@ -339,7 +322,8 @@ void dd_gatherv(gmx_domdec_t gmx_unused *dd,
         /* MPI does not allow NULL pointers */
         sbuf = &dum;
     }
-    MPI_Gatherv(sbuf, scount, MPI_BYTE,
+    /* Some MPI implementions don't specify const */
+    MPI_Gatherv(const_cast<void *>(sbuf), scount, MPI_BYTE,
                 rbuf, rcounts, disps, MPI_BYTE,
                 DDMASTERRANK(dd), dd->mpi_comm_all);
 #endif
index faf224c47089c50d31ec61acebbf699b7266bf32..7223336a8ec9220c4fdefe9589f1d11d2b2f561a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2008,2009,2010,2012,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2008,2009,2010,2012,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -123,11 +123,11 @@ dd_bcastc(struct gmx_domdec_t *dd, int nbytes, void *src, void *dest);
 
 /*! \brief Scatters \p nbytes from \p src on \p DDMASTERRANK to all PP ranks, received in \p dest */
 void
-dd_scatter(struct gmx_domdec_t *dd, int nbytes, void *src, void *dest);
+dd_scatter(struct gmx_domdec_t *dd, int nbytes, const void *src, void *dest);
 
 /*! \brief Gathers \p nbytes from \p src on all PP ranks, received in \p dest on \p DDMASTERRANK */
 void
-dd_gather(struct gmx_domdec_t *dd, int nbytes, void *src, void *dest);
+dd_gather(struct gmx_domdec_t *dd, int nbytes, const void *src, void *dest);
 
 /*! \brief Scatters \p scounts bytes from \p src on \p DDMASTERRANK to all PP ranks, receiving \p rcount bytes in \p dest.
  *
@@ -135,7 +135,7 @@ dd_gather(struct gmx_domdec_t *dd, int nbytes, void *src, void *dest);
  * If rcount==0, rbuf is allowed to be NULL */
 void
 dd_scatterv(struct gmx_domdec_t *dd,
-            int *scounts, int *disps, void *sbuf,
+            int *scounts, int *disps, const void *sbuf,
             int rcount, void *rbuf);
 
 /*! \brief Gathers \p rcount bytes from \p src on all PP ranks, received in \p scounts bytes in \p dest on \p DDMASTERRANK.
@@ -145,7 +145,7 @@ dd_scatterv(struct gmx_domdec_t *dd,
  * If scount==0, sbuf is allowed to be NULL */
 void
 dd_gatherv(struct gmx_domdec_t *dd,
-           int scount, void *sbuf,
+           int scount, const void *sbuf,
            int *rcounts, int *disps, void *rbuf);
 
 #endif
index 46b05ddd71ddf01e40ece4a02723cd8fa42f0143..79062a81225e793f21e924e7bf0f566078cbb716 100644 (file)
@@ -49,6 +49,8 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <cassert>
+
 #include <algorithm>
 #include <string>
 
@@ -419,7 +421,7 @@ void dd_print_missing_interactions(FILE *fplog, t_commrec *cr,
 
     print_missing_interactions_atoms(fplog, cr, top_global, &top_local->idef);
     write_dd_pdb("dd_dump_err", 0, "dump", top_global, cr,
-                 -1, state_local->x, state_local->box);
+                 -1, as_rvec_array(state_local->x.data()), state_local->box);
 
     std::string errorMessage;
 
@@ -503,7 +505,7 @@ static void count_excls(const t_block *cgs, const t_blocka *excls,
     }
 }
 
-/*! \brief Run the reverse ilist generation and store it when \p bAssign = TRUE */
+/*! \brief Run the reverse ilist generation and store it in r_il when \p bAssign = TRUE */
 static int low_make_reverse_ilist(const t_ilist *il_mt, const t_atom *atom,
                                   const int * const * vsite_pbc,
                                   int *count,
@@ -555,6 +557,8 @@ static int low_make_reverse_ilist(const t_ilist *il_mt, const t_atom *atom,
                     a = ia[1+link];
                     if (bAssign)
                     {
+                        assert(r_il); //with bAssign not allowed to be null
+                        assert(r_index);
                         r_il[r_index[a]+count[a]] =
                             (ftype == F_CONSTRNC ? F_CONSTR : ftype);
                         r_il[r_index[a]+count[a]+1] = ia[0];
@@ -2272,7 +2276,7 @@ void dd_init_local_state(gmx_domdec_t *dd,
         buf[1] = state_global->ngtc;
         buf[2] = state_global->nnhpres;
         buf[3] = state_global->nhchainlength;
-        buf[4] = state_global->dfhist.nlambda;
+        buf[4] = state_global->dfhist ? state_global->dfhist->nlambda : 0;
     }
     dd_bcast(dd, NITEM_DD_INIT_LOCAL_STATE*sizeof(int), buf);
 
index 41bbd3078e683f59f87c497f8db99faa5216cbf3..df8e76e4452ee820192d4545ea039e559fcdc5d1 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -53,6 +53,7 @@
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/math/vectypes.h"
+#include "gromacs/mdlib/broadcaststructs.h"
 #include "gromacs/mdlib/groupcoord.h"
 #include "gromacs/mdlib/mdrun.h"
 #include "gromacs/mdlib/sim_util.h"
@@ -61,7 +62,7 @@
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/pbcutil/pbc.h"
-#include "gromacs/topology/mtop_util.h"
+#include "gromacs/topology/mtop_lookup.h"
 #include "gromacs/topology/topology.h"
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/smalloc.h"
 
 
-/* We use the same defines as in broadcaststructs.cpp here */
-#define  block_bc(cr,   d) gmx_bcast(     sizeof(d),     &(d), (cr))
-#define nblock_bc(cr, nr, d) gmx_bcast((nr)*sizeof((d)[0]), (d), (cr))
-#define   snew_bc(cr, d, nr) { if (!MASTER(cr)) {snew((d), (nr)); }}
-
 /* enum to identify the type of ED: none, normal ED, flooding */
 enum {
     eEDnone, eEDedsam, eEDflood, eEDnr
@@ -1184,7 +1180,7 @@ static void get_flood_energies(t_edpar *edi, real Vfl[], int nnames)
 #endif
 
 
-gmx_edsam_t ed_open(int natoms, edsamstate_t *EDstate, int nfile, const t_filenm fnm[], unsigned long Flags, const gmx_output_env_t *oenv, t_commrec *cr)
+gmx_edsam_t ed_open(int natoms, edsamstate_t **EDstatePtr, int nfile, const t_filenm fnm[], unsigned long Flags, const gmx_output_env_t *oenv, t_commrec *cr)
 {
     gmx_edsam_t ed;
     int         nED;
@@ -1193,6 +1189,12 @@ gmx_edsam_t ed_open(int natoms, edsamstate_t *EDstate, int nfile, const t_filenm
     /* Allocate space for the ED data structure */
     snew(ed, 1);
 
+    if (*EDstatePtr == NULL)
+    {
+        snew(*EDstatePtr, 1);
+    }
+    edsamstate_t *EDstate = *EDstatePtr;
+
     /* We want to perform ED (this switch might later be upgraded to eEDflood) */
     ed->eEDtype = eEDedsam;
 
@@ -1361,23 +1363,19 @@ static void init_edi(const gmx_mtop_t *mtop, t_edpar *edi)
     int                   i;
     real                  totalmass = 0.0;
     rvec                  com;
-    gmx_mtop_atomlookup_t alook = NULL;
-    t_atom               *atom;
 
     /* NOTE Init_edi is executed on the master process only
      * The initialized data sets are then transmitted to the
      * other nodes in broadcast_ed_data */
 
-    alook = gmx_mtop_atomlookup_init(mtop);
-
     /* evaluate masses (reference structure) */
     snew(edi->sref.m, edi->sref.nr);
+    int molb = 0;
     for (i = 0; i < edi->sref.nr; i++)
     {
         if (edi->fitmas)
         {
-            gmx_mtop_atomnr_to_atom(alook, edi->sref.anrs[i], &atom);
-            edi->sref.m[i] = atom->m;
+            edi->sref.m[i] = mtopGetAtomMass(mtop, edi->sref.anrs[i], &molb);
         }
         else
         {
@@ -1404,11 +1402,10 @@ static void init_edi(const gmx_mtop_t *mtop, t_edpar *edi)
     snew(edi->sav.m, edi->sav.nr );
     for (i = 0; i < edi->sav.nr; i++)
     {
-        gmx_mtop_atomnr_to_atom(alook, edi->sav.anrs[i], &atom);
-        edi->sav.m[i] = atom->m;
+        edi->sav.m[i] = mtopGetAtomMass(mtop, edi->sav.anrs[i], &molb);
         if (edi->pcamas)
         {
-            edi->sav.sqrtm[i] = sqrt(atom->m);
+            edi->sav.sqrtm[i] = sqrt(edi->sav.m[i]);
         }
         else
         {
@@ -1422,12 +1419,10 @@ static void init_edi(const gmx_mtop_t *mtop, t_edpar *edi)
                       "For ED with mass-weighting, all average structure atoms need to have a mass >0.\n"
                       "Either make the covariance analysis non-mass-weighted, or exclude massless\n"
                       "atoms from the average structure by creating a proper index group.\n",
-                      i, edi->sav.anrs[i]+1, atom->m);
+                      i, edi->sav.anrs[i] + 1, edi->sav.m[i]);
         }
     }
 
-    gmx_mtop_atomlookup_destroy(alook);
-
     /* put reference structure in origin */
     get_center(edi->sref.x, edi->sref.m, edi->sref.nr, com);
     com[XX] = -com[XX];
index 57afb0fcf4b3dad17a52b793f30d0fbd69167c2b..ea87ceccbdba587e5e34352209db571cb5c5539d 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -88,7 +88,7 @@ void do_edsam(const t_inputrec *ir, gmx_int64_t step,
  * gmx make_edi can be used to create an .edi input file.
  *
  * \param natoms            Number of atoms of the whole MD system.
- * \param EDstate           Essential dynamics and flooding data stored in the checkpoint file.
+ * \param EDstatePtr        Essential dynamics and flooding data stored in the checkpoint file.
  * \param nfile             Number of entries (files) in the fnm structure.
  * \param fnm               The filenames struct; it contains also the names of the
  *                          essential dynamics and flooding in + output files.
@@ -98,7 +98,7 @@ void do_edsam(const t_inputrec *ir, gmx_int64_t step,
  * \param cr                Data needed for MPI communication.
  * \returns                 Pointer to the initialized essential dynamics / flooding data.
  */
-gmx_edsam_t ed_open(int natoms, edsamstate_t *EDstate, int nfile, const t_filenm fnm[],
+gmx_edsam_t ed_open(int natoms, edsamstate_t **EDstatePtr, int nfile, const t_filenm fnm[],
                     unsigned long Flags, const gmx_output_env_t *oenv, t_commrec *cr);
 
 /*! \brief Initializes the essential dynamics and flooding module.
index 89767dc67fa09262b2efc26bbab4b412805254c3..eba996c6e30337305e71d53dd5cd85b1b313a150 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/smalloc.h"
 
 #include "pme-internal.h"
 
-static void make_dft_mod(real *mod, real *data, int ndata)
+static void make_dft_mod(real *mod,
+                         const double *data, int splineOrder, int ndata)
 {
-    int  i, j;
-    real sc, ss, arg;
-
-    for (i = 0; i < ndata; i++)
+    for (int i = 0; i < ndata; i++)
     {
-        sc = ss = 0;
-        for (j = 0; j < ndata; j++)
+        /* We use double precision, since this is only called once per grid.
+         * But for single precision bsp_mod, single precision also seems
+         * to give full accuracy.
+         */
+        double sc = 0;
+        double ss = 0;
+        for (int j = 0; j < splineOrder; j++)
         {
-            arg = (2.0*M_PI*i*j)/ndata;
-            sc += data[j]*cos(arg);
-            ss += data[j]*sin(arg);
+            double arg  = (2.0*M_PI*i*(j + 1))/ndata;
+            sc         += data[j]*cos(arg);
+            ss         += data[j]*sin(arg);
         }
-        mod[i] = sc*sc+ss*ss;
+        mod[i] = sc*sc + ss*ss;
     }
-    for (i = 0; i < ndata; i++)
+    if (splineOrder % 2 == 0 && ndata % 2 == 0)
     {
-        if (mod[i] < 1e-7)
-        {
-            mod[i] = (mod[i-1]+mod[i+1])*0.5;
-        }
+        /* Note that pme_order = splineOrder + 1 */
+        GMX_RELEASE_ASSERT(mod[ndata/2] < GMX_DOUBLE_EPS, "With even spline order and even grid size (ndata), dft_mod[ndata/2] should first come out as zero");
+        /* This factor causes a division by zero. But since this occurs in
+         * the tail of the distribution, the term with this factor can
+         * be ignored (see Essmann et al. JCP 103, 8577).
+         * Using the average of the neighbors probably originates from
+         * Tom Darden's original PME code. It seems to give slighlty better
+         * accuracy than using a large value.
+         */
+        mod[ndata/2] = (mod[ndata/2 - 1] + mod[ndata/2 + 1])*0.5;
     }
 }
 
 void make_bspline_moduli(splinevec bsp_mod,
-                         int nx, int ny, int nz, int order)
+                         int nx, int ny, int nz, int pme_order)
 {
-    int   nmax = std::max(nx, std::max(ny, nz));
-    real *data, *ddata, *bsp_data;
-    int   i, k, l;
-    real  div;
+    /* We use double precision, since this is only called once per grid.
+     * But for single precision bsp_mod, single precision also seems
+     * to give full accuracy.
+     */
+    double *data;
 
-    snew(data, order);
-    snew(ddata, order);
-    snew(bsp_data, nmax);
+    /* In GROMACS we, confusingly, defined pme-order as the order
+     * of the cardinal B-spline + 1. This probably happened because
+     * the smooth PME paper only talks about "n" which is the number
+     * of points we spread to and that was chosen to be pme-order.
+     */
+    const int splineOrder = pme_order - 1;
 
-    data[order-1] = 0;
-    data[1]       = 0;
-    data[0]       = 1;
+    snew(data, splineOrder);
 
-    for (k = 3; k < order; k++)
+    data[0]     = 1;
+    for (int k = 1; k < splineOrder; k++)
     {
-        div       = 1.0/(k-1.0);
-        data[k-1] = 0;
-        for (l = 1; l < (k-1); l++)
-        {
-            data[k-l-1] = div*(l*data[k-l-2]+(k-l)*data[k-l-1]);
-        }
-        data[0] = div*data[0];
+        data[k] = 0;
     }
-    /* differentiate */
-    ddata[0] = -data[0];
-    for (k = 1; k < order; k++)
-    {
-        ddata[k] = data[k-1]-data[k];
-    }
-    div           = 1.0/(order-1);
-    data[order-1] = 0;
-    for (l = 1; l < (order-1); l++)
-    {
-        data[order-l-1] = div*(l*data[order-l-2]+(order-l)*data[order-l-1]);
-    }
-    data[0] = div*data[0];
 
-    for (i = 0; i < nmax; i++)
+    for (int k = 2; k <= splineOrder; k++)
     {
-        bsp_data[i] = 0;
-    }
-    for (i = 1; i <= order; i++)
-    {
-        bsp_data[i] = data[i-1];
+        double div  = 1.0/k;
+        for (int m = k - 1; m > 0; m--)
+        {
+            data[m] = div*((k - m)*data[m - 1] + (m + 1)*data[m]);
+        }
+        data[0]     = div*data[0];
     }
 
-    make_dft_mod(bsp_mod[XX], bsp_data, nx);
-    make_dft_mod(bsp_mod[YY], bsp_data, ny);
-    make_dft_mod(bsp_mod[ZZ], bsp_data, nz);
+    make_dft_mod(bsp_mod[XX], data, splineOrder, nx);
+    make_dft_mod(bsp_mod[YY], data, splineOrder, ny);
+    make_dft_mod(bsp_mod[ZZ], data, splineOrder, nz);
 
     sfree(data);
-    sfree(ddata);
-    sfree(bsp_data);
 }
 
 /* Return the P3M optimal influence function */
index ae5ff5ed23c2116d688420cff6852c0a1bbaab58..a37e6113cfc43b4ae0f8358e670ce54c88542968 100644 (file)
@@ -107,8 +107,9 @@ void ewald_LRcorrection(int numAtomsLocal,
     tensor      dxdf_q = {{0}}, dxdf_lj = {{0}};
     real        vol    = box[XX][XX]*box[YY][YY]*box[ZZ][ZZ];
     real        L1_q, L1_lj, dipole_coeff, qqA, qqB, qqL, vr0_q, vr0_lj = 0;
-    gmx_bool    bMolPBC      = fr->bMolPBC;
-    gmx_bool    bDoingLBRule = (fr->ljpme_combination_rule == eljpmeLB);
+    real        chargecorr[2] = { 0, 0 };
+    gmx_bool    bMolPBC       = fr->bMolPBC;
+    gmx_bool    bDoingLBRule  = (fr->ljpme_combination_rule == eljpmeLB);
     gmx_bool    bNeedLongRangeCorrection;
 
     /* This routine can be made faster by using tables instead of analytical interactions
@@ -157,9 +158,17 @@ void ewald_LRcorrection(int numAtomsLocal,
             }
             break;
         case eewg3DC:
-            dipole_coeff = 2*M_PI*one_4pi_eps/vol;
-            dipcorrA[ZZ] = 2*dipole_coeff*mutot[0][ZZ];
-            dipcorrB[ZZ] = 2*dipole_coeff*mutot[1][ZZ];
+            dipole_coeff  = 2*M_PI*one_4pi_eps/vol;
+            dipcorrA[ZZ]  = 2*dipole_coeff*mutot[0][ZZ];
+            dipcorrB[ZZ]  = 2*dipole_coeff*mutot[1][ZZ];
+            for (int q = 0; q < (bHaveChargeOrTypePerturbed ? 2 : 1); q++)
+            {
+                /* Avoid charge corrections with near-zero net charge */
+                if (fabs(fr->qsum[q]) > 1e-4)
+                {
+                    chargecorr[q] = 2*dipole_coeff*fr->qsum[q];
+                }
+            }
             break;
         default:
             gmx_incons("Unsupported Ewald geometry");
@@ -330,6 +339,10 @@ void ewald_LRcorrection(int numAtomsLocal,
                 {
                     f[i][j] -= dipcorrA[j]*chargeA[i];
                 }
+                if (chargecorr[0] != 0)
+                {
+                    f[i][ZZ] += chargecorr[0]*chargeA[i]*x[i][ZZ];
+                }
             }
         }
     }
@@ -478,6 +491,11 @@ void ewald_LRcorrection(int numAtomsLocal,
                     f[i][j] -= L1_q*dipcorrA[j]*chargeA[i]
                         + lambda_q*dipcorrB[j]*chargeB[i];
                 }
+                if (chargecorr[0] != 0 || chargecorr[1] != 0)
+                {
+                    f[i][ZZ] += (L1_q*chargecorr[0]*chargeA[i]
+                                 + lambda_q*chargecorr[1])*x[i][ZZ];
+                }
             }
         }
     }
@@ -510,8 +528,9 @@ void ewald_LRcorrection(int numAtomsLocal,
                 }
             }
 
-            /* Apply surface dipole correction:
-             * correction = dipole_coeff * (dipole)^2
+            /* Apply surface and charged surface dipole correction:
+             * correction = dipole_coeff * ( (dipole)^2
+             *              - qsum*sum_i q_i z_i^2 - qsum^2 * box_z^2 / 12 )
              */
             if (dipole_coeff != 0)
             {
@@ -522,6 +541,23 @@ void ewald_LRcorrection(int numAtomsLocal,
                 else if (ewald_geometry == eewg3DC)
                 {
                     Vdipole[q] = dipole_coeff*mutot[q][ZZ]*mutot[q][ZZ];
+
+                    if (chargecorr[q] != 0)
+                    {
+                        /* Here we use a non thread-parallelized loop,
+                         * because this is the only loop over atoms for
+                         * energies and they need reduction (unlike forces).
+                         * We could implement a reduction over threads,
+                         * but this case is rarely used.
+                         */
+                        const real *qPtr   = (q == 0 ? chargeA : chargeB);
+                        real        sumQZ2 = 0;
+                        for (int i = 0; i < numAtomsLocal; i++)
+                        {
+                            sumQZ2 += qPtr[i]*x[i][ZZ]*x[i][ZZ];
+                        }
+                        Vdipole[q] -= dipole_coeff*fr->qsum[q]*(sumQZ2 + fr->qsum[q]*box[ZZ][ZZ]*box[ZZ][ZZ]/12);
+                    }
                 }
             }
         }
index d4ec0d361913b12cb4ec22cfc5264caa6c8cd043..2e0b5b6cf9b5516c47a852f5e477ffddf74f6730 100644 (file)
@@ -44,6 +44,7 @@
 #include <cstdlib>
 
 #include "gromacs/ewald/pme.h"
+#include "gromacs/fft/parallel_3dfft.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/timing/cyclecounter.h"
 #include "gromacs/utility/fatalerror.h"
@@ -768,43 +769,38 @@ void pmegrids_init(pmegrids_t *grids,
 
 void pmegrids_destroy(pmegrids_t *grids)
 {
-    int t;
-
     if (grids->grid.grid != NULL)
     {
-        sfree(grids->grid.grid);
+        sfree_aligned(grids->grid.grid);
 
         if (grids->nthread > 0)
         {
-            for (t = 0; t < grids->nthread; t++)
-            {
-                sfree(grids->grid_th[t].grid);
-            }
+            sfree_aligned(grids->grid_all);
             sfree(grids->grid_th);
         }
     }
 }
 
 void
-make_gridindex5_to_localindex(int n, int local_start, int local_range,
-                              int **global_to_local,
-                              real **fraction_shift)
+make_gridindex_to_localindex(int n, int local_start, int local_range,
+                             int **global_to_local,
+                             real **fraction_shift)
 {
     /* Here we construct array for looking up the grid line index and
      * fraction for particles. This is done because it is slighlty
      * faster than the modulo operation and to because we need to take
      * care of rounding issues, see below.
-     * We use an array size of 5 times the grid size to allow for particles
-     * to be out of the triclinic unit-cell by up to 2 box lengths, which
-     * can be needed along dimension x for a very skewed unit-cell.
+     * We use an array size of c_pmeNeighborUnitcellCount times the grid size
+     * to allow for particles to be out of the triclinic unit-cell.
      */
-    int  * gtl;
-    real * fsh;
+    const int arraySize = c_pmeNeighborUnitcellCount * n;
+    int     * gtl;
+    real    * fsh;
 
-    snew(gtl, 5*n);
-    snew(fsh, 5*n);
+    snew(gtl, arraySize);
+    snew(fsh, arraySize);
 
-    for (int i = 0; i < 5*n; i++)
+    for (int i = 0; i < arraySize; i++)
     {
         /* Transform global grid index to the local grid index.
          * Our local grid always runs from 0 to local_range-1.
@@ -864,6 +860,7 @@ void reuse_pmegrids(const pmegrids_t *oldgrid, pmegrids_t *newgrid)
     if (newgrid->grid_th != NULL && newgrid->nthread == oldgrid->nthread)
     {
         sfree_aligned(newgrid->grid_all);
+        newgrid->grid_all = oldgrid->grid_all;
         for (t = 0; t < newgrid->nthread; t++)
         {
             newgrid->grid_th[t].grid = oldgrid->grid_th[t].grid;
index ed91fd2125e0aed2af60e0a89712a9dd4bbb8022..adb958bc61a989908b90ebb42e8b02343eed0e71 100644 (file)
 
 #include "pme-internal.h"
 
+
+/*! \brief
+ * We allow coordinates to be out the unit-cell by up to 2 box lengths,
+ * which might be needed along dimension x for a very skewed unit-cell.
+ */
+constexpr int c_pmeMaxUnitcellShift = 2;
+
+/*! \brief
+ * This affects the size of the lookup table of the modulo operation result,
+ * when working with PME local grid indices of the particles.
+ */
+constexpr int c_pmeNeighborUnitcellCount = 2*c_pmeMaxUnitcellShift + 1;
+
+
 #if GMX_MPI
 void
 gmx_sum_qgrid_dd(struct gmx_pme_t *pme, real *grid, int direction);
@@ -83,9 +97,9 @@ void
 pmegrids_destroy(pmegrids_t *grids);
 
 void
-make_gridindex5_to_localindex(int n, int local_start, int local_range,
-                              int **global_to_local,
-                              real **fraction_shift);
+make_gridindex_to_localindex(int n, int local_start, int local_range,
+                             int **global_to_local,
+                             real **fraction_shift);
 
 void
 set_grid_alignment(int *pmegrid_nz, int pme_order);
index a74070a431d2d33b465cb2148796ab8858a8d339..804003edde225dd51b8d33903394e1551894777e 100644 (file)
 
 #include <stdio.h>
 
-#include "gromacs/fft/parallel_3dfft.h"
 #include "gromacs/math/gmxcomplex.h"
 #include "gromacs/timing/wallcycle.h"
 #include "gromacs/timing/walltime_accounting.h"
 #include "gromacs/utility/gmxmpi.h"
 
+//! A repeat of typedef from parallel_3dfft.h
+typedef struct gmx_parallel_3dfft *gmx_parallel_3dfft_t;
+
 struct t_commrec;
 struct t_inputrec;
 
@@ -94,12 +96,17 @@ static const real lb_scale_factor_symm[] = { 2.0/64, 12.0/64, 30.0/64, 20.0/64 }
  */
 #define PME_ORDER_MAX 12
 
-/*! \brief As gmx_pme_init, but takes most settings, except the grid, from pme_src */
+/*! \brief As gmx_pme_init, but takes most settings, except the grid/Ewald coefficients, from pme_src.
+ * This is only called when the PME cut-off/grid size changes.
+ */
 int gmx_pme_reinit(struct gmx_pme_t **pmedata,
                    t_commrec *        cr,
                    struct gmx_pme_t * pme_src,
                    const t_inputrec * ir,
-                   ivec               grid_size);
+                   ivec               grid_size,
+                   real               ewaldcoeff_q,
+                   real               ewaldcoeff_lj);
+
 
 /* The following three routines are for PME/PP node splitting in pme_pp.c */
 
@@ -244,12 +251,16 @@ typedef struct gmx_pme_t {
     int        nthread;       /* The number of threads doing PME on our rank */
 
     gmx_bool   bPPnode;       /* Node also does particle-particle forces */
+    bool       doCoulomb;     /* Apply PME to electrostatics */
+    bool       doLJ;          /* Apply PME to Lennard-Jones r^-6 interactions */
     gmx_bool   bFEP;          /* Compute Free energy contribution */
     gmx_bool   bFEP_q;
     gmx_bool   bFEP_lj;
     int        nkx, nky, nkz; /* Grid dimensions */
     gmx_bool   bP3M;          /* Do P3M: optimize the influence function */
     int        pme_order;
+    real       ewaldcoeff_q;  /* Ewald splitting coefficient for Coulomb */
+    real       ewaldcoeff_lj; /* Ewald splitting coefficient for r^-6 */
     real       epsilon_r;
 
     int        ljpme_combination_rule;  /* Type of combination rule in LJ-PME */
@@ -365,9 +376,8 @@ int gmx_pme_recv_coeffs_coords(struct gmx_pme_pp *pme_pp,
                                real **sigmaA, real **sigmaB,
                                matrix box, rvec **x, rvec **f,
                                int *maxshift_x, int *maxshift_y,
-                               gmx_bool *bFreeEnergy_q, gmx_bool *bFreeEnergy_lj,
                                real *lambda_q, real *lambda_lj,
-                               gmx_bool *bEnerVir, int *pme_flags,
+                               gmx_bool *bEnerVir,
                                gmx_int64_t *step,
                                ivec grid_size, real *ewaldcoeff_q, real *ewaldcoeff_lj);
 
index a028c1cb987b011236930bf7075969c2d9996284..ed4e6e038dc6430ce10f6d3a0fece02f219a8adf 100644 (file)
@@ -57,7 +57,6 @@
 #include "gromacs/domdec/domdec_network.h"
 #include "gromacs/domdec/domdec_struct.h"
 #include "gromacs/fft/calcgrid.h"
-#include "gromacs/gmxlib/md_logging.h"
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/math/functions.h"
 #include "gromacs/math/vec.h"
@@ -72,6 +71,7 @@
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/logger.h"
 #include "gromacs/utility/smalloc.h"
 
 #include "pme-internal.h"
@@ -155,11 +155,11 @@ bool pme_loadbal_is_active(const pme_load_balancing_t *pme_lb)
 
 void pme_loadbal_init(pme_load_balancing_t     **pme_lb_p,
                       t_commrec                 *cr,
-                      FILE                      *fp_log,
+                      const gmx::MDLogger       &mdlog,
                       const t_inputrec          *ir,
                       matrix                     box,
                       const interaction_const_t *ic,
-                      struct gmx_pme_t          *pmedata,
+                      gmx_pme_t                 *pmedata,
                       gmx_bool                   bUseGPU,
                       gmx_bool                  *bPrinting)
 {
@@ -244,7 +244,7 @@ void pme_loadbal_init(pme_load_balancing_t     **pme_lb_p,
 
     if (!wallcycle_have_counter())
     {
-        md_print_warn(cr, fp_log, "NOTE: Cycle counters unsupported or not enabled in kernel. Cannot use PME-PP balancing.\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText("NOTE: Cycle counters unsupported or not enabled in kernel. Cannot use PME-PP balancing.");
     }
 
     /* Tune with GPUs and/or separate PME ranks.
@@ -274,7 +274,7 @@ void pme_loadbal_init(pme_load_balancing_t     **pme_lb_p,
         dd_dlb_lock(cr->dd);
         if (dd_dlb_is_locked(cr->dd))
         {
-            md_print_warn(cr, fp_log, "NOTE: DLB will not turn on during the first phase of PME tuning\n");
+            GMX_LOG(mdlog.warning).asParagraph().appendText("NOTE: DLB will not turn on during the first phase of PME tuning");
         }
     }
 
@@ -518,6 +518,7 @@ pme_load_balance(pme_load_balancing_t      *pme_lb,
                  t_commrec                 *cr,
                  FILE                      *fp_err,
                  FILE                      *fp_log,
+                 const gmx::MDLogger       &mdlog,
                  const t_inputrec          *ir,
                  t_state                   *state,
                  double                     cycles,
@@ -746,7 +747,8 @@ pme_load_balance(pme_load_balancing_t      *pme_lb,
                 /* This should not happen, as we set limits on the DLB bounds.
                  * But we implement a complete failsafe solution anyhow.
                  */
-                md_print_warn(cr, fp_log, "The fastest PP/PME load balancing setting (cutoff %.3f nm) is no longer available due to DD DLB or box size limitations\n");
+                GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                        "The fastest PP/PME load balancing setting (cutoff %.3f nm) is no longer available due to DD DLB or box size limitations", pme_lb->fastest);
                 pme_lb->fastest = pme_lb->lower_limit;
                 pme_lb->start   = pme_lb->lower_limit;
             }
@@ -820,7 +822,7 @@ pme_load_balance(pme_load_balancing_t      *pme_lb,
              */
             gmx_pme_reinit(&set->pmedata,
                            cr, pme_lb->setup[0].pmedata, ir,
-                           set->grid);
+                           set->grid, set->ewaldcoeff_q, set->ewaldcoeff_lj);
         }
         *pmedata = set->pmedata;
     }
@@ -870,6 +872,7 @@ void pme_loadbal_do(pme_load_balancing_t *pme_lb,
                     t_commrec            *cr,
                     FILE                 *fp_err,
                     FILE                 *fp_log,
+                    const gmx::MDLogger  &mdlog,
                     const t_inputrec     *ir,
                     t_forcerec           *fr,
                     t_state              *state,
@@ -951,7 +954,7 @@ void pme_loadbal_do(pme_load_balancing_t *pme_lb,
         {
             /* Unlock the DLB=auto, DLB is allowed to activate */
             dd_dlb_unlock(cr->dd);
-            md_print_warn(cr, fp_log, "NOTE: DLB can now turn on, when beneficial\n");
+            GMX_LOG(mdlog.warning).asParagraph().appendText("NOTE: DLB can now turn on, when beneficial");
 
             /* We don't deactivate the tuning yet, since we will balance again
              * after DLB gets turned on, if it does within PMETune_period.
@@ -984,7 +987,7 @@ void pme_loadbal_do(pme_load_balancing_t *pme_lb,
          * but the first data collected is skipped anyhow.
          */
         pme_load_balance(pme_lb, cr,
-                         fp_err, fp_log,
+                         fp_err, fp_log, mdlog,
                          ir, state, pme_lb->cycles_c - cycles_prev,
                          fr->ic, fr->nbv, &fr->pmedata,
                          step);
@@ -1015,7 +1018,7 @@ void pme_loadbal_do(pme_load_balancing_t *pme_lb,
     {
         /* Make sure DLB is allowed when we deactivate PME tuning */
         dd_dlb_unlock(cr->dd);
-        md_print_warn(cr, fp_log, "NOTE: DLB can now turn on, when beneficial\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText("NOTE: DLB can now turn on, when beneficial");
     }
 
     *bPrinting = pme_lb->bBalance;
@@ -1042,8 +1045,8 @@ static void print_pme_loadbal_setting(FILE              *fplog,
 
 /*! \brief Print all load-balancing settings */
 static void print_pme_loadbal_settings(pme_load_balancing_t *pme_lb,
-                                       t_commrec            *cr,
                                        FILE                 *fplog,
+                                       const gmx::MDLogger  &mdlog,
                                        gmx_bool              bNonBondedOnGPU)
 {
     double     pp_ratio, grid_ratio;
@@ -1081,10 +1084,10 @@ static void print_pme_loadbal_settings(pme_load_balancing_t *pme_lb,
 
     if (pp_ratio > 1.5 && !bNonBondedOnGPU)
     {
-        md_print_warn(cr, fplog,
-                      "NOTE: PME load balancing increased the non-bonded workload by more than 50%%.\n"
-                      "      For better performance, use (more) PME ranks (mdrun -npme),\n"
-                      "      or if you are beyond the scaling limit, use fewer total ranks (or nodes).\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText(
+                "NOTE: PME load balancing increased the non-bonded workload by more than 50%.\n"
+                "      For better performance, use (more) PME ranks (mdrun -npme),\n"
+                "      or if you are beyond the scaling limit, use fewer total ranks (or nodes).");
     }
     else
     {
@@ -1093,13 +1096,13 @@ static void print_pme_loadbal_settings(pme_load_balancing_t *pme_lb,
 }
 
 void pme_loadbal_done(pme_load_balancing_t *pme_lb,
-                      t_commrec            *cr,
                       FILE                 *fplog,
+                      const gmx::MDLogger  &mdlog,
                       gmx_bool              bNonBondedOnGPU)
 {
     if (fplog != NULL && (pme_lb->cur > 0 || pme_lb->elimited != epmelblimNO))
     {
-        print_pme_loadbal_settings(pme_lb, cr, fplog, bNonBondedOnGPU);
+        print_pme_loadbal_settings(pme_lb, fplog, mdlog, bNonBondedOnGPU);
     }
 
     /* TODO: Here we should free all pointers in pme_lb,
index d0e305a8eb91f248dbe2f40942a8340927b1fbb0..80ddbbebb3b6c2ac2c2b468b6efa44bb8b067a29 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 struct t_commrec;
 struct t_inputrec;
 
+namespace gmx
+{
+class MDLogger;
+}
+
 /*! \brief Object to manage PME load balancing */
 struct pme_load_balancing_t;
 
@@ -69,12 +74,12 @@ bool pme_loadbal_is_active(const pme_load_balancing_t *pme_lb);
  * usage.
  */
 void pme_loadbal_init(pme_load_balancing_t     **pme_lb_p,
-                      struct t_commrec          *cr,
-                      FILE                      *fp_log,
+                      t_commrec                 *cr,
+                      const gmx::MDLogger       &mdlog,
                       const t_inputrec          *ir,
                       matrix                     box,
                       const interaction_const_t *ic,
-                      struct gmx_pme_t          *pmedata,
+                      gmx_pme_t                 *pmedata,
                       gmx_bool                   bUseGPU,
                       gmx_bool                  *bPrinting);
 
@@ -89,6 +94,7 @@ void pme_loadbal_do(pme_load_balancing_t  *pme_lb,
                     struct t_commrec      *cr,
                     FILE                  *fp_err,
                     FILE                  *fp_log,
+                    const gmx::MDLogger   &mdlog,
                     const t_inputrec      *ir,
                     t_forcerec            *fr,
                     t_state               *state,
@@ -99,8 +105,8 @@ void pme_loadbal_do(pme_load_balancing_t  *pme_lb,
 
 /*! \brief Finish the PME load balancing and print the settings when fplog!=NULL */
 void pme_loadbal_done(pme_load_balancing_t *pme_lb,
-                      struct t_commrec     *cr,
                       FILE                 *fplog,
+                      const gmx::MDLogger  &mdlog,
                       gmx_bool              bNonBondedOnGPU);
 
 #endif
index 326cf977f97c56aa20c0e62d444fed4d1af5ad9c..6d8c0984357626a346079437b562ad4a3adcfcf2 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -107,6 +107,7 @@ static void reset_pmeonly_counters(gmx_wallcycle_t wcycle,
 
 static void gmx_pmeonly_switch(int *npmedata, struct gmx_pme_t ***pmedata,
                                ivec grid_size,
+                               real ewaldcoeff_q, real ewaldcoeff_lj,
                                t_commrec *cr, t_inputrec *ir,
                                struct gmx_pme_t **pme_ret)
 {
@@ -133,7 +134,7 @@ static void gmx_pmeonly_switch(int *npmedata, struct gmx_pme_t ***pmedata,
     srenew(*pmedata, *npmedata);
 
     /* Generate a new PME data structure, copying part of the old pointers */
-    gmx_pme_reinit(&((*pmedata)[ind]), cr, pme, ir, grid_size);
+    gmx_pme_reinit(&((*pmedata)[ind]), cr, pme, ir, grid_size, ewaldcoeff_q, ewaldcoeff_lj);
 
     *pme_ret = (*pmedata)[ind];
 }
@@ -163,7 +164,6 @@ int gmx_pmeonly(struct gmx_pme_t *pme,
     float              cycles;
     int                count;
     gmx_bool           bEnerVir;
-    int                pme_flags;
     gmx_int64_t        step;
     ivec               grid_switch;
 
@@ -190,17 +190,15 @@ int gmx_pmeonly(struct gmx_pme_t *pme,
                                              &sigmaA, &sigmaB,
                                              box, &x_pp, &f_pp,
                                              &maxshift_x, &maxshift_y,
-                                             &pme->bFEP_q, &pme->bFEP_lj,
                                              &lambda_q, &lambda_lj,
                                              &bEnerVir,
-                                             &pme_flags,
                                              &step,
                                              grid_switch, &ewaldcoeff_q, &ewaldcoeff_lj);
 
             if (ret == pmerecvqxSWITCHGRID)
             {
                 /* Switch the PME grid to grid_switch */
-                gmx_pmeonly_switch(&npmedata, &pmedata, grid_switch, cr, ir, &pme);
+                gmx_pmeonly_switch(&npmedata, &pmedata, grid_switch, ewaldcoeff_q, ewaldcoeff_lj, cr, ir, &pme);
             }
 
             if (ret == pmerecvqxRESETCOUNTERS)
@@ -233,9 +231,9 @@ int gmx_pmeonly(struct gmx_pme_t *pme,
         gmx_pme_do(pme, 0, natoms, x_pp, f_pp,
                    chargeA, chargeB, c6A, c6B, sigmaA, sigmaB, box,
                    cr, maxshift_x, maxshift_y, mynrnb, wcycle,
-                   vir_q, ewaldcoeff_q, vir_lj, ewaldcoeff_lj,
+                   vir_q, vir_lj,
                    &energy_q, &energy_lj, lambda_q, lambda_lj, &dvdlambda_q, &dvdlambda_lj,
-                   pme_flags | GMX_PME_DO_ALL_F | (bEnerVir ? GMX_PME_CALC_ENER_VIR : 0));
+                   GMX_PME_DO_ALL_F | (bEnerVir ? GMX_PME_CALC_ENER_VIR : 0));
 
         cycles = wallcycle_stop(wcycle, ewcPMEMESH);
 
index d7642deda6f85c3c606e5d8da53ede11bdcb02d5..daa937b57164ab60f445b40589704d7e827ec362 100644 (file)
@@ -79,9 +79,6 @@ enum {
  *
  * Some parts of the code(gmx_pme_send_q, gmx_pme_recv_q_x) assume
  * that the six first flags are exactly in this order.
- * If more PP_PME_...-flags are to be introduced be aware of some of
- * the PME-specific flags in pme.h. Currently, they are also passed
- * through here.
  */
 
 #define PP_PME_CHARGE         (1<<0)
@@ -91,8 +88,6 @@ enum {
 #define PP_PME_SIGMA          (1<<4)
 #define PP_PME_SIGMAB         (1<<5)
 #define PP_PME_COORD          (1<<6)
-#define PP_PME_FEP_Q          (1<<7)
-#define PP_PME_FEP_LJ         (1<<8)
 #define PP_PME_ENER_VIR       (1<<9)
 #define PP_PME_FINISH         (1<<10)
 #define PP_PME_SWITCHGRID     (1<<11)
@@ -111,7 +106,6 @@ struct gmx_pme_pp {
     int         *node;           /**< The PP node ranks                          */
     int          node_peer;      /**< The peer PP node rank                      */
     int         *nat;            /**< The number of atom for each PP node        */
-    int          flags_charge;   /**< The flags sent along with the last charges */
     //@{
     /**< Vectors of A- and B-state parameters used to transfer vectors to PME ranks  */
     real        *chargeA;
@@ -141,7 +135,7 @@ struct gmx_pme_comm_n_box_t {
     int             maxshift_y; /**< Maximum shift in y direction */
     real            lambda_q;   /**< Free-energy lambda for electrostatics */
     real            lambda_lj;  /**< Free-energy lambda for Lennard-Jones */
-    int             flags;      /**< Control flags */
+    unsigned int    flags;      /**< Control flags */
     gmx_int64_t     step;       /**< MD integration step number */
     //@{
     /*! \brief Used in PME grid tuning */
@@ -182,7 +176,6 @@ gmx_pme_pp_t gmx_pme_pp_init(t_commrec *cr)
     snew(pme_pp->req, eCommType_NR*pme_pp->nnode);
     snew(pme_pp->stat, eCommType_NR*pme_pp->nnode);
     pme_pp->nalloc       = 0;
-    pme_pp->flags_charge = 0;
 #else
     GMX_UNUSED_VALUE(cr);
 #endif
@@ -207,7 +200,7 @@ static void gmx_pme_send_coeffs_coords_wait(gmx_domdec_t gmx_unused *dd)
 }
 
 /*! \brief Send data to PME ranks */
-static void gmx_pme_send_coeffs_coords(t_commrec *cr, int flags,
+static void gmx_pme_send_coeffs_coords(t_commrec *cr, unsigned int flags,
                                        real gmx_unused *chargeA, real gmx_unused *chargeB,
                                        real gmx_unused *c6A, real gmx_unused *c6B,
                                        real gmx_unused *sigmaA, real gmx_unused *sigmaB,
@@ -339,9 +332,8 @@ void gmx_pme_send_parameters(t_commrec *cr,
                              real *sigmaA, real *sigmaB,
                              int maxshift_x, int maxshift_y)
 {
-    int flags;
+    unsigned int flags = 0;
 
-    flags = 0;
     if (EEL_PME(ic->eeltype))
     {
         flags |= PP_PME_CHARGE;
@@ -364,22 +356,11 @@ void gmx_pme_send_parameters(t_commrec *cr,
 }
 
 void gmx_pme_send_coordinates(t_commrec *cr, matrix box, rvec *x,
-                              gmx_bool bFreeEnergy_q, gmx_bool bFreeEnergy_lj,
                               real lambda_q, real lambda_lj,
-                              gmx_bool bEnerVir, int pme_flags,
+                              gmx_bool bEnerVir,
                               gmx_int64_t step)
 {
-    int flags;
-
-    flags = pme_flags | PP_PME_COORD;
-    if (bFreeEnergy_q)
-    {
-        flags |= PP_PME_FEP_Q;
-    }
-    if (bFreeEnergy_lj)
-    {
-        flags |= PP_PME_FEP_LJ;
-    }
+    unsigned int flags = PP_PME_COORD;
     if (bEnerVir)
     {
         flags |= PP_PME_ENER_VIR;
@@ -390,9 +371,7 @@ void gmx_pme_send_coordinates(t_commrec *cr, matrix box, rvec *x,
 
 void gmx_pme_send_finish(t_commrec *cr)
 {
-    int flags;
-
-    flags = PP_PME_FINISH;
+    unsigned int flags = PP_PME_FINISH;
 
     gmx_pme_send_coeffs_coords(cr, flags, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, -1);
 }
@@ -451,34 +430,36 @@ int gmx_pme_recv_coeffs_coords(struct gmx_pme_pp *pme_pp,
                                rvec             **f,
                                int               *maxshift_x,
                                int               *maxshift_y,
-                               gmx_bool          *bFreeEnergy_q,
-                               gmx_bool          *bFreeEnergy_lj,
                                real              *lambda_q,
                                real              *lambda_lj,
                                gmx_bool          *bEnerVir,
-                               int               *pme_flags,
                                gmx_int64_t       *step,
                                ivec               grid_size,
                                real              *ewaldcoeff_q,
                                real              *ewaldcoeff_lj)
 {
-    int                  nat = 0, status;
+    int status = -1;
+    int nat    = 0;
 
-    *pme_flags = 0;
 #if GMX_MPI
-    gmx_pme_comm_n_box_t cnb;
-    int                  messages;
+    unsigned int flags    = 0;
+    int          messages = 0;
 
-    cnb.flags  = 0;
-    messages   = 0;
     do
     {
+        gmx_pme_comm_n_box_t cnb;
+        cnb.flags = 0;
 
         /* Receive the send count, box and time step from the peer PP node */
         MPI_Recv(&cnb, sizeof(cnb), MPI_BYTE,
                  pme_pp->node_peer, eCommType_CNB,
                  pme_pp->mpi_comm_mysim, MPI_STATUS_IGNORE);
 
+        /* We accumulate all received flags */
+        flags |= cnb.flags;
+
+        *step  = cnb.step;
+
         if (debug)
         {
             fprintf(debug, "PME only rank receiving:%s%s%s%s%s\n",
@@ -489,21 +470,25 @@ int gmx_pme_recv_coeffs_coords(struct gmx_pme_pp *pme_pp,
                     (cnb.flags & PP_PME_RESETCOUNTERS) ? " reset counters" : "");
         }
 
+        if (cnb.flags & PP_PME_FINISH)
+        {
+            status = pmerecvqxFINISH;
+        }
+
         if (cnb.flags & PP_PME_SWITCHGRID)
         {
             /* Special case, receive the new parameters and return */
             copy_ivec(cnb.grid_size, grid_size);
             *ewaldcoeff_q  = cnb.ewaldcoeff_q;
             *ewaldcoeff_lj = cnb.ewaldcoeff_lj;
-            return pmerecvqxSWITCHGRID;
+
+            status         = pmerecvqxSWITCHGRID;
         }
 
         if (cnb.flags & PP_PME_RESETCOUNTERS)
         {
-            /* Special case, receive the step and return */
-            *step = cnb.step;
-
-            return pmerecvqxRESETCOUNTERS;
+            /* Special case, receive the step (set above) and return */
+            status = pmerecvqxRESETCOUNTERS;
         }
 
         if (cnb.flags & (PP_PME_CHARGE | PP_PME_SQRTC6 | PP_PME_SIGMA))
@@ -608,41 +593,17 @@ int gmx_pme_recv_coeffs_coords(struct gmx_pme_pp *pme_pp,
                     }
                 }
             }
-
-            pme_pp->flags_charge = cnb.flags;
         }
 
         if (cnb.flags & PP_PME_COORD)
         {
-            if (!(pme_pp->flags_charge & (PP_PME_CHARGE | PP_PME_SQRTC6)))
-            {
-                gmx_incons("PME-only rank received coordinates before charges and/or C6-values"
-                           );
-            }
-
             /* The box, FE flag and lambda are sent along with the coordinates
              *  */
             copy_mat(cnb.box, box);
-            *bFreeEnergy_q  = ((cnb.flags & GMX_PME_DO_COULOMB) &&
-                               (cnb.flags & PP_PME_FEP_Q));
-            *bFreeEnergy_lj = ((cnb.flags & GMX_PME_DO_LJ) &&
-                               (cnb.flags & PP_PME_FEP_LJ));
             *lambda_q       = cnb.lambda_q;
             *lambda_lj      = cnb.lambda_lj;
             *bEnerVir       = (cnb.flags & PP_PME_ENER_VIR);
-            *pme_flags      = cnb.flags;
-
-            if (*bFreeEnergy_q && !(pme_pp->flags_charge & PP_PME_CHARGEB))
-            {
-                gmx_incons("PME-only rank received free energy request, but "
-                           "did not receive B-state charges");
-            }
-
-            if (*bFreeEnergy_lj && !(pme_pp->flags_charge & PP_PME_SQRTC6B))
-            {
-                gmx_incons("PME-only rank received free energy request, but "
-                           "did not receive B-state C6-values");
-            }
+            *step           = cnb.step;
 
             /* Receive the coordinates in place */
             nat = 0;
@@ -663,22 +624,19 @@ int gmx_pme_recv_coeffs_coords(struct gmx_pme_pp *pme_pp,
                     }
                 }
             }
+
+            status = pmerecvqxX;
         }
 
         /* Wait for the coordinates and/or charges to arrive */
         MPI_Waitall(messages, pme_pp->req, pme_pp->stat);
         messages = 0;
     }
-    while (!(cnb.flags & (PP_PME_COORD | PP_PME_FINISH)));
-    status = ((cnb.flags & PP_PME_FINISH) ? pmerecvqxFINISH : pmerecvqxX);
-
-    *step = cnb.step;
+    while (status == -1);
 #else
     GMX_UNUSED_VALUE(box);
     GMX_UNUSED_VALUE(maxshift_x);
     GMX_UNUSED_VALUE(maxshift_y);
-    GMX_UNUSED_VALUE(bFreeEnergy_q);
-    GMX_UNUSED_VALUE(bFreeEnergy_lj);
     GMX_UNUSED_VALUE(lambda_q);
     GMX_UNUSED_VALUE(lambda_lj);
     GMX_UNUSED_VALUE(bEnerVir);
@@ -690,15 +648,18 @@ int gmx_pme_recv_coeffs_coords(struct gmx_pme_pp *pme_pp,
     status = pmerecvqxX;
 #endif
 
-    *natoms   = nat;
-    *chargeA  = pme_pp->chargeA;
-    *chargeB  = pme_pp->chargeB;
-    *sqrt_c6A = pme_pp->sqrt_c6A;
-    *sqrt_c6B = pme_pp->sqrt_c6B;
-    *sigmaA   = pme_pp->sigmaA;
-    *sigmaB   = pme_pp->sigmaB;
-    *x        = pme_pp->x;
-    *f        = pme_pp->f;
+    if (status == pmerecvqxX)
+    {
+        *natoms   = nat;
+        *chargeA  = pme_pp->chargeA;
+        *chargeB  = pme_pp->chargeB;
+        *sqrt_c6A = pme_pp->sqrt_c6A;
+        *sqrt_c6B = pme_pp->sqrt_c6B;
+        *sigmaA   = pme_pp->sigmaA;
+        *sigmaB   = pme_pp->sigmaB;
+        *x        = pme_pp->x;
+        *f        = pme_pp->f;
+    }
 
     return status;
 }
index a7599b029e36be538079db4bfe1c43e6b94d670f..71553ad7a2d51ee41a2b502a3d898649df4c0afb 100644 (file)
@@ -159,7 +159,7 @@ void pme_free_all_work(struct pme_solve_work_t **work, int nthread)
     {
         free_work(&(*work)[thread]);
     }
-    sfree(work);
+    sfree(*work);
     *work = NULL;
 }
 
@@ -287,8 +287,7 @@ gmx_inline static void calc_exponentials_lj(int start, int end, real *r, real *t
 }
 #endif
 
-int solve_pme_yzx(struct gmx_pme_t *pme, t_complex *grid,
-                  real ewaldcoeff, real vol,
+int solve_pme_yzx(struct gmx_pme_t *pme, t_complex *grid, real vol,
                   gmx_bool bEnerVir,
                   int nthread, int thread)
 {
@@ -298,7 +297,8 @@ int solve_pme_yzx(struct gmx_pme_t *pme, t_complex *grid,
     int                      kx, ky, kz, maxkx, maxky;
     int                      nx, ny, nz, iyz0, iyz1, iyz, iy, iz, kxstart, kxend;
     real                     mx, my, mz;
-    real                     factor = M_PI*M_PI/(ewaldcoeff*ewaldcoeff);
+    real                     ewaldcoeff = pme->ewaldcoeff_q;
+    real                     factor     = M_PI*M_PI/(ewaldcoeff*ewaldcoeff);
     real                     ets2, struct2, vfactor, ets2vf;
     real                     d1, d2, energy = 0;
     real                     by, bz;
@@ -538,8 +538,7 @@ int solve_pme_yzx(struct gmx_pme_t *pme, t_complex *grid,
     return local_ndata[YY]*local_ndata[XX];
 }
 
-int solve_pme_lj_yzx(struct gmx_pme_t *pme, t_complex **grid, gmx_bool bLB,
-                     real ewaldcoeff, real vol,
+int solve_pme_lj_yzx(struct gmx_pme_t *pme, t_complex **grid, gmx_bool bLB, real vol,
                      gmx_bool bEnerVir, int nthread, int thread)
 {
     /* do recip sum over local cells in grid */
@@ -548,7 +547,8 @@ int solve_pme_lj_yzx(struct gmx_pme_t *pme, t_complex **grid, gmx_bool bLB,
     int                      kx, ky, kz, maxkx, maxky;
     int                      nx, ny, nz, iy, iyz0, iyz1, iyz, iz, kxstart, kxend;
     real                     mx, my, mz;
-    real                     factor = M_PI*M_PI/(ewaldcoeff*ewaldcoeff);
+    real                     ewaldcoeff = pme->ewaldcoeff_lj;
+    real                     factor     = M_PI*M_PI/(ewaldcoeff*ewaldcoeff);
     real                     ets2, ets2vf;
     real                     eterm, vterm, d1, d2, energy = 0;
     real                     by, bz;
index 6b26a58f1bc37df9b0ac46c5475d0b663b22ae5a..33c828a39d58db951039b6dca8a3945739d699ad 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -70,12 +70,12 @@ void get_pme_ener_vir_lj(struct pme_solve_work_t *work, int nthread,
                          real *mesh_energy, matrix vir);
 
 int solve_pme_yzx(struct gmx_pme_t *pme, t_complex *grid,
-                  real ewaldcoeff, real vol,
+                  real vol,
                   gmx_bool bEnerVir,
                   int nthread, int thread);
 
 int solve_pme_lj_yzx(struct gmx_pme_t *pme, t_complex **grid, gmx_bool bLB,
-                     real ewaldcoeff, real vol,
+                     real vol,
                      gmx_bool bEnerVir, int nthread, int thread);
 
 #endif
index 94cf25a97d446673e1128a502681c0b68cc66495..5bb4be177ba0a9269c40cd0b98cac1ffd9f7e598 100644 (file)
 #include <algorithm>
 
 #include "gromacs/ewald/pme.h"
+#include "gromacs/fft/parallel_3dfft.h"
 #include "gromacs/simd/simd.h"
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/smalloc.h"
 
+#include "pme-grid.h"
 #include "pme-internal.h"
 #include "pme-simd.h"
 #include "pme-spline-work.h"
@@ -100,20 +102,22 @@ static void calc_interpolation_idx(struct gmx_pme_t *pme, pme_atomcomm_t *atc,
         }
     }
 
+    const real shift = c_pmeMaxUnitcellShift;
+
     for (i = start; i < end; i++)
     {
         xptr   = atc->x[i];
         idxptr = atc->idx[i];
         fptr   = atc->fractx[i];
 
-        /* Fractional coordinates along box vectors, add 2.0 to make 100% sure we are positive for triclinic boxes */
-        tx = nx * ( xptr[XX] * rxx + xptr[YY] * ryx + xptr[ZZ] * rzx + 2.0 );
-        ty = ny * (                  xptr[YY] * ryy + xptr[ZZ] * rzy + 2.0 );
-        tz = nz * (                                   xptr[ZZ] * rzz + 2.0 );
+        /* Fractional coordinates along box vectors, add a positive shift to ensure tx/ty/tz are positive for triclinic boxes */
+        tx = nx * ( xptr[XX] * rxx + xptr[YY] * ryx + xptr[ZZ] * rzx + shift );
+        ty = ny * (                  xptr[YY] * ryy + xptr[ZZ] * rzy + shift );
+        tz = nz * (                                   xptr[ZZ] * rzz + shift );
 
-        tix = (int)(tx);
-        tiy = (int)(ty);
-        tiz = (int)(tz);
+        tix = static_cast<int>(tx);
+        tiy = static_cast<int>(ty);
+        tiz = static_cast<int>(tz);
 
         /* Because decomposition only occurs in x and y,
          * we never have a fraction correction in z.
index 5824e580ada49cc7b693832127decb1e0d3b802c..d33dd55759508bde5fb63de49da38d0a315d8479 100644 (file)
@@ -150,38 +150,6 @@ static void setup_coordinate_communication(pme_atomcomm_t *atc)
     }
 }
 
-int gmx_pme_destroy(FILE *log, struct gmx_pme_t **pmedata)
-{
-    int i;
-
-    if (NULL != log)
-    {
-        fprintf(log, "Destroying PME data structures.\n");
-    }
-
-    sfree((*pmedata)->nnx);
-    sfree((*pmedata)->nny);
-    sfree((*pmedata)->nnz);
-
-    for (i = 0; i < (*pmedata)->ngrids; ++i)
-    {
-        pmegrids_destroy(&(*pmedata)->pmegrid[i]);
-        sfree((*pmedata)->fftgrid[i]);
-        sfree((*pmedata)->cfftgrid[i]);
-        gmx_parallel_3dfft_destroy((*pmedata)->pfft_setup[i]);
-    }
-
-    sfree((*pmedata)->lb_buf1);
-    sfree((*pmedata)->lb_buf2);
-
-    pme_free_all_work(&(*pmedata)->solve_work, (*pmedata)->nthread);
-
-    sfree(*pmedata);
-    *pmedata = NULL;
-
-    return 0;
-}
-
 /*! \brief Round \p n up to the next multiple of \p f */
 static int mult_up(int n, int f)
 {
@@ -266,6 +234,48 @@ static void init_atomcomm(struct gmx_pme_t *pme, pme_atomcomm_t *atc,
     }
 }
 
+/*! \brief Destroy an atom communication data structure and its child structs */
+static void destroy_atomcomm(pme_atomcomm_t *atc)
+{
+    sfree(atc->pd);
+    if (atc->nslab > 1)
+    {
+        sfree(atc->node_dest);
+        sfree(atc->node_src);
+        for (int i = 0; i < atc->nthread; i++)
+        {
+            sfree(atc->count_thread[i]);
+        }
+        sfree(atc->count_thread);
+        sfree(atc->rcount);
+        sfree(atc->buf_index);
+
+        sfree(atc->x);
+        sfree(atc->coefficient);
+        sfree(atc->f);
+    }
+    sfree(atc->idx);
+    sfree(atc->fractx);
+
+    sfree(atc->thread_idx);
+    for (int i = 0; i < atc->nthread; i++)
+    {
+        if (atc->nthread > 1)
+        {
+            int *n_ptr = atc->thread_plist[i].n - gmxCacheLineSize;
+            sfree(n_ptr);
+            sfree(atc->thread_plist[i].i);
+        }
+        sfree(atc->spline[i].thread_one);
+        sfree(atc->spline[i].ind);
+    }
+    if (atc->nthread > 1)
+    {
+        sfree(atc->thread_plist);
+    }
+    sfree(atc->spline);
+}
+
 /*! \brief Initialize data structure for communication */
 static void
 init_overlap_comm(pme_overlap_t *  ol,
@@ -399,6 +409,19 @@ init_overlap_comm(pme_overlap_t *  ol,
     snew(ol->recvbuf, norder*commplainsize);
 }
 
+/*! \brief Destroy data structure for communication */
+static void
+destroy_overlap_comm(const pme_overlap_t *ol)
+{
+    sfree(ol->s2g0);
+    sfree(ol->s2g1);
+    sfree(ol->send_id);
+    sfree(ol->recv_id);
+    sfree(ol->comm_data);
+    sfree(ol->sendbuf);
+    sfree(ol->recvbuf);
+}
+
 void gmx_pme_check_restrictions(int pme_order,
                                 int nkx, int nky, int nkz,
                                 int nnodes_major,
@@ -469,6 +492,8 @@ int gmx_pme_init(struct gmx_pme_t **pmedata,
                  gmx_bool           bFreeEnergy_q,
                  gmx_bool           bFreeEnergy_lj,
                  gmx_bool           bReproducible,
+                 real               ewaldcoeff_q,
+                 real               ewaldcoeff_lj,
                  int                nthread)
 {
     struct gmx_pme_t *pme = NULL;
@@ -591,17 +616,29 @@ int gmx_pme_init(struct gmx_pme_t **pmedata,
         gmx_fatal(FARGS, "pme does not (yet) work with pbc = screw");
     }
 
-    pme->bFEP_q      = ((ir->efep != efepNO) && bFreeEnergy_q);
-    pme->bFEP_lj     = ((ir->efep != efepNO) && bFreeEnergy_lj);
-    pme->bFEP        = (pme->bFEP_q || pme->bFEP_lj);
-    pme->nkx         = ir->nkx;
-    pme->nky         = ir->nky;
-    pme->nkz         = ir->nkz;
-    pme->bP3M        = (ir->coulombtype == eelP3M_AD || getenv("GMX_PME_P3M") != NULL);
-    pme->pme_order   = ir->pme_order;
+    /* NOTE:
+     * It is likely that the current gmx_pme_do() routine supports calculating
+     * only Coulomb or LJ while gmx_pme_init() configures for both,
+     * but that has never been tested.
+     * It is likely that the current gmx_pme_do() routine supports calculating,
+     * not calculating free-energy for Coulomb and/or LJ while gmx_pme_init()
+     * configures with free-energy, but that has never been tested.
+     */
+    pme->doCoulomb     = EEL_PME(ir->coulombtype);
+    pme->doLJ          = EVDW_PME(ir->vdwtype);
+    pme->bFEP_q        = ((ir->efep != efepNO) && bFreeEnergy_q);
+    pme->bFEP_lj       = ((ir->efep != efepNO) && bFreeEnergy_lj);
+    pme->bFEP          = (pme->bFEP_q || pme->bFEP_lj);
+    pme->nkx           = ir->nkx;
+    pme->nky           = ir->nky;
+    pme->nkz           = ir->nkz;
+    pme->bP3M          = (ir->coulombtype == eelP3M_AD || getenv("GMX_PME_P3M") != NULL);
+    pme->pme_order     = ir->pme_order;
+    pme->ewaldcoeff_q  = ewaldcoeff_q;
+    pme->ewaldcoeff_lj = ewaldcoeff_lj;
 
     /* Always constant electrostatics coefficients */
-    pme->epsilon_r   = ir->epsilon_r;
+    pme->epsilon_r     = ir->epsilon_r;
 
     /* Always constant LJ coefficients */
     pme->ljpme_combination_rule = ir->ljpme_combination_rule;
@@ -698,18 +735,18 @@ int gmx_pme_init(struct gmx_pme_t **pmedata,
     pme->pmegrid_start_iy = pme->overlap[1].s2g0[pme->nodeid_minor];
     pme->pmegrid_start_iz = 0;
 
-    make_gridindex5_to_localindex(pme->nkx,
-                                  pme->pmegrid_start_ix,
-                                  pme->pmegrid_nx - (pme->pme_order-1),
-                                  &pme->nnx, &pme->fshx);
-    make_gridindex5_to_localindex(pme->nky,
-                                  pme->pmegrid_start_iy,
-                                  pme->pmegrid_ny - (pme->pme_order-1),
-                                  &pme->nny, &pme->fshy);
-    make_gridindex5_to_localindex(pme->nkz,
-                                  pme->pmegrid_start_iz,
-                                  pme->pmegrid_nz_base,
-                                  &pme->nnz, &pme->fshz);
+    make_gridindex_to_localindex(pme->nkx,
+                                 pme->pmegrid_start_ix,
+                                 pme->pmegrid_nx - (pme->pme_order-1),
+                                 &pme->nnx, &pme->fshx);
+    make_gridindex_to_localindex(pme->nky,
+                                 pme->pmegrid_start_iy,
+                                 pme->pmegrid_ny - (pme->pme_order-1),
+                                 &pme->nny, &pme->fshy);
+    make_gridindex_to_localindex(pme->nkz,
+                                 pme->pmegrid_start_iz,
+                                 pme->pmegrid_nz_base,
+                                 &pme->nnz, &pme->fshz);
 
     pme->spline_work = make_pme_spline_work(pme->pme_order);
 
@@ -719,7 +756,7 @@ int gmx_pme_init(struct gmx_pme_t **pmedata,
     /* It doesn't matter if we allocate too many grids here,
      * we only allocate and use the ones we need.
      */
-    if (EVDW_PME(ir->vdwtype))
+    if (pme->doLJ)
     {
         pme->ngrids = ((ir->ljpme_combination_rule == eljpmeLB) ? DO_Q_AND_LJ_LB : DO_Q_AND_LJ);
     }
@@ -733,11 +770,11 @@ int gmx_pme_init(struct gmx_pme_t **pmedata,
 
     for (i = 0; i < pme->ngrids; ++i)
     {
-        if ((i <  DO_Q && EEL_PME(ir->coulombtype) && (i == 0 ||
-                                                       bFreeEnergy_q)) ||
-            (i >= DO_Q && EVDW_PME(ir->vdwtype) && (i == 2 ||
-                                                    bFreeEnergy_lj ||
-                                                    ir->ljpme_combination_rule == eljpmeLB)))
+        if ((i <  DO_Q && pme->doCoulomb && (i == 0 ||
+                                             bFreeEnergy_q)) ||
+            (i >= DO_Q && pme->doLJ && (i == 2 ||
+                                        bFreeEnergy_lj ||
+                                        ir->ljpme_combination_rule == eljpmeLB)))
         {
             pmegrids_init(&pme->pmegrid[i],
                           pme->pmegrid_nx, pme->pmegrid_ny, pme->pmegrid_nz,
@@ -795,7 +832,9 @@ int gmx_pme_reinit(struct gmx_pme_t **pmedata,
                    t_commrec *        cr,
                    struct gmx_pme_t * pme_src,
                    const t_inputrec * ir,
-                   ivec               grid_size)
+                   ivec               grid_size,
+                   real               ewaldcoeff_q,
+                   real               ewaldcoeff_lj)
 {
     t_inputrec irc;
     int        homenr;
@@ -816,7 +855,7 @@ int gmx_pme_reinit(struct gmx_pme_t **pmedata,
     }
 
     ret = gmx_pme_init(pmedata, cr, pme_src->nnodes_major, pme_src->nnodes_minor,
-                       &irc, homenr, pme_src->bFEP_q, pme_src->bFEP_lj, FALSE, pme_src->nthread);
+                       &irc, homenr, pme_src->bFEP_q, pme_src->bFEP_lj, FALSE, ewaldcoeff_q, ewaldcoeff_lj, pme_src->nthread);
 
     if (ret == 0)
     {
@@ -901,8 +940,7 @@ int gmx_pme_do(struct gmx_pme_t *pme,
                matrix box,      t_commrec *cr,
                int  maxshift_x, int maxshift_y,
                t_nrnb *nrnb,    gmx_wallcycle_t wcycle,
-               matrix vir_q,    real ewaldcoeff_q,
-               matrix vir_lj,   real ewaldcoeff_lj,
+               matrix vir_q,    matrix vir_lj,
                real *energy_q,  real *energy_lj,
                real lambda_q,   real lambda_lj,
                real *dvdlambda_q, real *dvdlambda_lj,
@@ -971,7 +1009,7 @@ int gmx_pme_do(struct gmx_pme_t *pme,
      * that don't yet have them.
      */
 
-    bDoSplines = pme->bFEP || ((flags & GMX_PME_DO_COULOMB) && (flags & GMX_PME_DO_LJ));
+    bDoSplines = pme->bFEP || (pme->doCoulomb && pme->doLJ);
 
     /* We need a maximum of four separate PME calculations:
      * grid_index=0: Coulomb PME with charges from state A
@@ -992,9 +1030,9 @@ int gmx_pme_do(struct gmx_pme_t *pme,
          * If grid_index < 2 we should be doing electrostatic PME
          * If grid_index >= 2 we should be doing LJ-PME
          */
-        if ((grid_index <  DO_Q && (!(flags & GMX_PME_DO_COULOMB) ||
+        if ((grid_index <  DO_Q && (!pme->doCoulomb ||
                                     (grid_index == 1 && !pme->bFEP_q))) ||
-            (grid_index >= DO_Q && (!(flags & GMX_PME_DO_LJ) ||
+            (grid_index >= DO_Q && (!pme->doLJ ||
                                     (grid_index == 3 && !pme->bFEP_lj))))
         {
             continue;
@@ -1119,7 +1157,7 @@ int gmx_pme_do(struct gmx_pme_t *pme,
                     if (grid_index < DO_Q)
                     {
                         loop_count =
-                            solve_pme_yzx(pme, cfftgrid, ewaldcoeff_q,
+                            solve_pme_yzx(pme, cfftgrid,
                                           box[XX][XX]*box[YY][YY]*box[ZZ][ZZ],
                                           bCalcEnerVir,
                                           pme->nthread, thread);
@@ -1127,7 +1165,7 @@ int gmx_pme_do(struct gmx_pme_t *pme,
                     else
                     {
                         loop_count =
-                            solve_pme_lj_yzx(pme, &cfftgrid, FALSE, ewaldcoeff_lj,
+                            solve_pme_lj_yzx(pme, &cfftgrid, FALSE,
                                              box[XX][XX]*box[YY][YY]*box[ZZ][ZZ],
                                              bCalcEnerVir,
                                              pme->nthread, thread);
@@ -1245,7 +1283,7 @@ int gmx_pme_do(struct gmx_pme_t *pme,
     /* For Lorentz-Berthelot combination rules in LJ-PME, we need to calculate
      * seven terms. */
 
-    if ((flags & GMX_PME_DO_LJ) && pme->ljpme_combination_rule == eljpmeLB)
+    if (pme->doLJ && pme->ljpme_combination_rule == eljpmeLB)
     {
         /* Loop over A- and B-state if we are doing FEP */
         for (fep_state = 0; fep_state < fep_states_lj; ++fep_state)
@@ -1398,7 +1436,7 @@ int gmx_pme_do(struct gmx_pme_t *pme,
                         }
 
                         loop_count =
-                            solve_pme_lj_yzx(pme, &pme->cfftgrid[2], TRUE, ewaldcoeff_lj,
+                            solve_pme_lj_yzx(pme, &pme->cfftgrid[2], TRUE,
                                              box[XX][XX]*box[YY][YY]*box[ZZ][ZZ],
                                              bCalcEnerVir,
                                              pme->nthread, thread);
@@ -1423,7 +1461,7 @@ int gmx_pme_do(struct gmx_pme_t *pme,
 
             if (bBackFFT)
             {
-                bFirst = !(flags & GMX_PME_DO_COULOMB);
+                bFirst = !pme->doCoulomb;
                 calc_initial_lb_coeffs(pme, local_c6, local_sigma);
                 for (grid_index = 8; grid_index >= 2; --grid_index)
                 {
@@ -1541,7 +1579,7 @@ int gmx_pme_do(struct gmx_pme_t *pme,
 
     if (bCalcEnerVir)
     {
-        if (flags & GMX_PME_DO_COULOMB)
+        if (pme->doCoulomb)
         {
             if (!pme->bFEP_q)
             {
@@ -1571,7 +1609,7 @@ int gmx_pme_do(struct gmx_pme_t *pme,
             *energy_q = 0;
         }
 
-        if (flags & GMX_PME_DO_LJ)
+        if (pme->doLJ)
         {
             if (!pme->bFEP_lj)
             {
@@ -1602,3 +1640,45 @@ int gmx_pme_do(struct gmx_pme_t *pme,
     }
     return 0;
 }
+
+int gmx_pme_destroy(struct gmx_pme_t **pmedata)
+{
+    struct gmx_pme_t *pme = *pmedata;
+
+    sfree(pme->nnx);
+    sfree(pme->nny);
+    sfree(pme->nnz);
+    sfree(pme->fshx);
+    sfree(pme->fshy);
+    sfree(pme->fshz);
+
+    for (int i = 0; i < pme->ngrids; ++i)
+    {
+        pmegrids_destroy(&pme->pmegrid[i]);
+        gmx_parallel_3dfft_destroy(pme->pfft_setup[i]);
+    }
+
+    for (int i = 0; i < pme->ndecompdim; i++)
+    {
+        destroy_atomcomm(&pme->atc[i]);
+    }
+
+    destroy_overlap_comm(&pme->overlap[0]);
+    destroy_overlap_comm(&pme->overlap[1]);
+
+    sfree(pme->lb_buf1);
+    sfree(pme->lb_buf2);
+
+    sfree(pme->bufv);
+    sfree(pme->bufr);
+
+    pme_free_all_work(&pme->solve_work, pme->nthread);
+
+    sfree(pme->sum_qgrid_tmp);
+    sfree(pme->sum_qgrid_dd_tmp);
+
+    sfree(*pmedata);
+    *pmedata = NULL;
+
+    return 0;
+}
index 9f4f06375bfad374afaff5fd91d9e976b0921f1c..2712cc7e56bdbdc6fc8f381897c14642e6b55220 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -74,13 +74,15 @@ int gmx_pme_init(struct gmx_pme_t **pmedata, struct t_commrec *cr,
                  int nnodes_major, int nnodes_minor,
                  t_inputrec *ir, int homenr,
                  gmx_bool bFreeEnergy_q, gmx_bool bFreeEnergy_lj,
-                 gmx_bool bReproducible, int nthread);
+                 gmx_bool bReproducible,
+                 real ewaldcoeff_q, real ewaldcoeff_lj,
+                 int nthread);
 
-/*! \brief Destroy the pme data structures resepectively.
+/*! \brief Destroy the PME data structures respectively.
  *
  * \return 0 indicates all well, non zero is an error code.
  */
-int gmx_pme_destroy(FILE *log, struct gmx_pme_t **pmedata);
+int gmx_pme_destroy(struct gmx_pme_t **pmedata);
 
 //@{
 /*! \brief Flag values that control what gmx_pme_do() will calculate
@@ -94,12 +96,6 @@ int gmx_pme_destroy(FILE *log, struct gmx_pme_t **pmedata);
 /* This forces the grid to be backtransformed even without GMX_PME_CALC_F */
 #define GMX_PME_CALC_POT      (1<<4)
 
-/* These values label bits used for sending messages to PME nodes using the
- * routines in pme_pp.c and shouldn't conflict with the flags used there
- */
-#define GMX_PME_DO_COULOMB    (1<<13)
-#define GMX_PME_DO_LJ         (1<<14)
-
 #define GMX_PME_DO_ALL_F  (GMX_PME_SPREAD | GMX_PME_SOLVE | GMX_PME_CALC_F)
 //@}
 
@@ -119,8 +115,7 @@ int gmx_pme_do(struct gmx_pme_t *pme,
                matrix box,      t_commrec *cr,
                int  maxshift_x, int maxshift_y,
                t_nrnb *nrnb,    gmx_wallcycle_t wcycle,
-               matrix vir_q,    real ewaldcoeff_q,
-               matrix vir_lj,   real ewaldcoeff_lj,
+               matrix vir_q,    matrix vir_lj,
                real *energy_q,  real *energy_lj,
                real lambda_q,   real lambda_lj,
                real *dvdlambda_q, real *dvdlambda_lj,
@@ -155,9 +150,8 @@ void gmx_pme_send_parameters(struct t_commrec *cr,
 
 /*! \brief Send the coordinates to our PME-only node and request a PME calculation */
 void gmx_pme_send_coordinates(struct t_commrec *cr, matrix box, rvec *x,
-                              gmx_bool bFreeEnergy_q, gmx_bool bFreeEnergy_lj,
                               real lambda_q, real lambda_lj,
-                              gmx_bool bEnerVir, int pme_flags,
+                              gmx_bool bEnerVir,
                               gmx_int64_t step);
 
 /*! \brief Tell our PME-only node to finish */
index ac194ab3e9e1241bd7eb94171927998b974bb225..9a55150b6f003470861fa8b789d82aaa93785957 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 1991-2003 David van der Spoel, Erik Lindahl, University of Groningen.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -391,7 +391,7 @@ gmx_fft_2d_real          (gmx_fft_t                  fft,
                 }
             }
         }
-        data = (t_complex *)out_data;
+        data = static_cast<t_complex *>(out_data);
 
         /* y real-to-complex FFTs */
         for (i = 0; i < nx; i++)
@@ -425,12 +425,12 @@ gmx_fft_2d_real          (gmx_fft_t                  fft,
         if (in_data != out_data)
         {
             memcpy(work, in_data, sizeof(t_complex)*nx*nyc);
-            data = (t_complex *)work;
+            data = reinterpret_cast<t_complex *>(work);
         }
         else
         {
             /* in-place */
-            data = (t_complex *)out_data;
+            data = reinterpret_cast<t_complex *>(out_data);
         }
 
         /* Transpose to get X arrays */
index ee86ced85eae5838fce51a24f9c59888a411441c..a120ee5d00e4b9f20034dab0ce085d2b50cbc237 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 1991-2003 David van der Spoel, Erik Lindahl, University of Groningen.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -111,9 +111,9 @@ struct gmx_fft
 
 
 int
-gmx_fft_init_1d(gmx_fft_t *        pfft,
-                int                nx,
-                gmx_fft_flag       flags)
+gmx_fft_init_1d(gmx_fft_t *             pfft,
+                int                     nx,
+                gmx_fft_flag gmx_unused flags)
 {
     gmx_fft_t      fft;
     int            d;
@@ -187,9 +187,9 @@ gmx_fft_init_1d(gmx_fft_t *        pfft,
 
 
 int
-gmx_fft_init_1d_real(gmx_fft_t *        pfft,
-                     int                nx,
-                     gmx_fft_flag       flags)
+gmx_fft_init_1d_real(gmx_fft_t *             pfft,
+                     int                     nx,
+                     gmx_fft_flag gmx_unused flags)
 {
     gmx_fft_t      fft;
     int            d;
@@ -271,10 +271,10 @@ gmx_fft_init_1d_real(gmx_fft_t *        pfft,
 
 
 int
-gmx_fft_init_2d_real(gmx_fft_t *        pfft,
-                     int                nx,
-                     int                ny,
-                     gmx_fft_flag       flags)
+gmx_fft_init_2d_real(gmx_fft_t *             pfft,
+                     int                     nx,
+                     int                     ny,
+                     gmx_fft_flag gmx_unused flags)
 {
     gmx_fft_t      fft;
     int            d;
@@ -424,10 +424,12 @@ gmx_fft_init_2d_real(gmx_fft_t *        pfft,
 
     if (status == 0)
     {
-        if ((fft->work = (t_complex *)malloc(sizeof(t_complex)*(nx*(ny/2+1)))) == NULL)
+        void *memory = malloc(sizeof(t_complex)*(nx*(ny/2+1)));
+        if (nullptr == memory)
         {
             status = ENOMEM;
         }
+        fft->work = static_cast<t_complex *>(memory);
     }
 
     if (status != 0)
index 117e19c56d4f6e908703c70a3a04575a15bd9575..b7ca96feceb31d24f09c6edfbe34fc39ef3bc939 100644 (file)
@@ -60,13 +60,6 @@ gmx_install_headers(
     xvgr.h
     )
 
-if (GMX_USE_TNG AND TNG_IO_DEFINITIONS)
-    set_property(SOURCE tngio.cpp
-                 APPEND PROPERTY COMPILE_DEFINITIONS ${TNG_IO_DEFINITIONS})
-    set_property(SOURCE tngio_for_tools.cpp
-                 APPEND PROPERTY COMPILE_DEFINITIONS ${TNG_IO_DEFINITIONS})
-endif()
-
 if (BUILD_TESTING)
      add_subdirectory(tests)
 endif()
index eb07c8ed68a61bd8a974f4a48eb156c2d431cad2..4530329127de6fda1f46db101f194abaecf64387 100644 (file)
@@ -60,6 +60,7 @@
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/math/vecdump.h"
+#include "gromacs/math/vectypes.h"
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/mdtypes/df_history.h"
 #include "gromacs/mdtypes/energyhistory.h"
@@ -71,6 +72,7 @@
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/futil.h"
+#include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/int64_to_int.h"
 #include "gromacs/utility/programcontext.h"
 #include "gromacs/utility/smalloc.h"
@@ -149,29 +151,33 @@ const char *edfh_names[edfhNR] =
     "accumulated_plus", "accumulated_minus", "accumulated_plus_2",  "accumulated_minus_2", "Tij", "Tij_empirical"
 };
 
-enum {
-    ecprREAL, ecprRVEC, ecprMATRIX
+//! Higher level vector element type, only used for formatting checkpoint dumps
+enum class CptElementType
+{
+    integer,   //!< integer
+    real,      //!< float or double, not linked to precision of type real
+    real3,     //!< float[3] or double[3], not linked to precision of type real
+    matrix3x3  //!< float[3][3] or double[3][3], not linked to precision of type real
 };
 
-enum {
-    cptpEST, cptpEEKS, cptpEENH, cptpEDFH
+//! \brief Parts of the checkpoint state, only used for reporting
+enum class StatePart
+{
+    microState,       //!< The microstate of the simulated system
+    kineticEnergy,    //!< Kinetic energy, needed for T/P-coupling state
+    energyHistory,    //!< Energy observable statistics
+    freeEnergyHistory //!< Free-energy state and observable statistics
 };
-/* enums for the different components of checkpoint variables, replacing the hard coded ones.
-   cptpEST - state variables.
-   cptpEEKS - Kinetic energy state variables.
-   cptpEENH - Energy history state variables.
-   cptpEDFH - free energy history variables.
- */
 
-
-static const char *st_names(int cptp, int ecpt)
+//! \brief Return the name of a checkpoint entry based on part and part entry
+static const char *entryName(StatePart part, int ecpt)
 {
-    switch (cptp)
+    switch (part)
     {
-        case cptpEST: return est_names [ecpt];
-        case cptpEEKS: return eeks_names[ecpt];
-        case cptpEENH: return eenh_names[ecpt];
-        case cptpEDFH: return edfh_names[ecpt];
+        case StatePart::microState:        return est_names [ecpt];
+        case StatePart::kineticEnergy:     return eeks_names[ecpt];
+        case StatePart::energyHistory:     return eenh_names[ecpt];
+        case StatePart::freeEnergyHistory: return edfh_names[ecpt];
     }
 
     return NULL;
@@ -307,345 +313,421 @@ static void do_cpt_n_rvecs_err(XDR *xd, const char *desc, int n, rvec f[], FILE
     }
 }
 
-/* If nval >= 0, nval is used; on read this should match the passed value.
- * If nval n<0, *nptr is used; on read the value is stored in nptr
+template <typename T>
+struct xdr_type
+{
+};
+
+template <>
+struct xdr_type<int>
+{
+    // cppcheck-suppress unusedStructMember
+    static const int value = xdr_datatype_int;
+};
+
+template <>
+struct xdr_type<float>
+{
+    // cppcheck-suppress unusedStructMember
+    static const int value = xdr_datatype_float;
+};
+
+template <>
+struct xdr_type<double>
+{
+    // cppcheck-suppress unusedStructMember
+    static const int value = xdr_datatype_double;
+};
+
+//! \brief Returns size in byte of an xdr_datatype
+static inline unsigned int sizeOfXdrType(int xdrType)
+{
+    switch (xdrType)
+    {
+        case xdr_datatype_int:
+            return sizeof(int);
+            break;
+        case xdr_datatype_float:
+            return sizeof(float);
+            break;
+        case xdr_datatype_double:
+            return sizeof(double);
+            break;
+        default: GMX_RELEASE_ASSERT(false, "XDR data type not implemented");
+    }
+
+    return 0;
+}
+
+//! \brief Returns the XDR process function for i/o of an XDR type
+static inline xdrproc_t xdrProc(int xdrType)
+{
+    switch (xdrType)
+    {
+        case xdr_datatype_int:
+            return reinterpret_cast<xdrproc_t>(xdr_int);
+            break;
+        case xdr_datatype_float:
+            return reinterpret_cast<xdrproc_t>(xdr_float);
+            break;
+        case xdr_datatype_double:
+            return reinterpret_cast<xdrproc_t>(xdr_double);
+            break;
+        default: GMX_RELEASE_ASSERT(false, "XDR data type not implemented");
+    }
+
+    return NULL;
+}
+
+/*! \brief Lists or only reads an xdr vector from checkpoint file
+ *
+ * When list!=NULL reads and lists the \p nf vector elements of type \p xdrType.
+ * The header for the print is set by \p part and \p ecpt.
+ * The formatting of the printing is set by \p cptElementType.
+ * When list==NULL only reads the elements.
  */
-static int do_cpte_reals_low(XDR *xd, int cptp, int ecpt, int sflags,
-                             int nval, int *nptr, real **v,
-                             FILE *list, int erealtype)
+static bool_t listXdrVector(XDR *xd, StatePart part, int ecpt, int nf, int xdrType,
+                            FILE *list, CptElementType cptElementType)
 {
-    bool_t     res       = 0;
-    const bool useDouble = GMX_DOUBLE;
-    int        dtc       = useDouble ? xdr_datatype_double : xdr_datatype_float;
-    real      *vp, *va = NULL;
-    float     *vf;
-    double    *vd;
-    int        nf, dt, i;
+    bool_t             res = 0;
 
-    if (list == NULL)
+    const unsigned int elemSize = sizeOfXdrType(xdrType);
+    std::vector<char>  data(nf*elemSize);
+    res = xdr_vector(xd, data.data(), nf, elemSize, xdrProc(xdrType));
+
+    if (list != NULL)
     {
-        if (nval >= 0)
+        switch (xdrType)
         {
-            nf = nval;
-        }
-        else
-        {
-            if (nptr == NULL)
-            {
-                gmx_incons("*ntpr=NULL in do_cpte_reals_low");
-            }
-            nf = *nptr;
+            case xdr_datatype_int:
+                pr_ivec(list, 0, entryName(part, ecpt), reinterpret_cast<const int *>(data.data()), nf, TRUE);
+                break;
+            case xdr_datatype_float:
+#if !GMX_DOUBLE
+                if (cptElementType == CptElementType::real3)
+                {
+                    // cppcheck-suppress invalidPointerCast
+                    pr_rvecs(list, 0, entryName(part, ecpt), reinterpret_cast<const rvec *>(data.data()), nf/3);
+                }
+                else
+#endif
+                {
+                    /* Note: With double precision code dumping a single precision rvec will produce float iso rvec print, but that's a minor annoyance */
+                    // cppcheck-suppress invalidPointerCast
+                    pr_fvec(list, 0, entryName(part, ecpt), reinterpret_cast<const float *>(data.data()), nf, TRUE);
+                }
+                break;
+            case xdr_datatype_double:
+#if GMX_DOUBLE
+                if (cptElementType == CptElementType::real3)
+                {
+                    // cppcheck-suppress invalidPointerCast
+                    pr_rvecs(list, 0, entryName(part, ecpt), reinterpret_cast<const rvec *>(data.data()), nf/3);
+                }
+                else
+#endif
+                {
+                    /* Note: With single precision code dumping a double precision rvec will produce float iso rvec print, but that's a minor annoyance */
+                    // cppcheck-suppress invalidPointerCast
+                    pr_dvec(list, 0, entryName(part, ecpt), reinterpret_cast<const double *>(data.data()), nf, TRUE);
+                }
+                break;
+            default: GMX_RELEASE_ASSERT(false, "Data type not implemented for listing");
         }
     }
-    res = xdr_int(xd, &nf);
-    if (res == 0)
+
+    return res;
+}
+
+//! \brief Convert a double array, typed char*, to float
+static void convertArrayRealPrecision(const char *c, float *v, int n)
+{
+    const double *d = reinterpret_cast<const double *>(c);
+    for (int i = 0; i < n; i++)
     {
-        return -1;
+        v[i] = static_cast<float>(d[i]);
     }
+}
+
+//! \brief Convert a float array, typed char*, to double
+static void convertArrayRealPrecision(const char *c, double *v, int n)
+{
+    const float *f = reinterpret_cast<const float *>(c);
+    for (int i = 0; i < n; i++)
+    {
+        v[i] = static_cast<double>(f[i]);
+    }
+}
+
+//! \brief Generate an error for trying to convert to integer
+static void convertArrayRealPrecision(const char gmx_unused *c, int gmx_unused *v, int gmx_unused n)
+{
+    GMX_RELEASE_ASSERT(false, "We only expect type mismatches between float and double, not integer");
+}
+
+/*! \brief Low-level routine for reading/writing a vector of reals from/to file.
+ *
+ * This is the only routine that does the actually i/o of real vector,
+ * all other routines are intermediate level routines for specific real
+ * data types, calling this routine.
+ * Currently this routine is (too) complex, since it handles both real *
+ * and std::vector<real>. Using real * is deprecated and this routine
+ * will simplify a lot when only std::vector needs to be supported.
+ *
+ * When not listing, we use either v or vector, depending on which is !=NULL.
+ * If nval >= 0, nval is used; on read this should match the passed value.
+ * If nval n<0, *nptr (with v) or vector->size() is used. On read using v,
+ * the value is stored in nptr
+ */
+template<typename T>
+static int doVectorLow(XDR *xd, StatePart part, int ecpt, int sflags,
+                       int nval, int *nptr,
+                       T **v, std::vector<T> *vector,
+                       FILE *list, CptElementType cptElementType)
+{
+    GMX_RELEASE_ASSERT(list != NULL || (v != NULL && vector == NULL) || (v == NULL && vector != NULL), "Without list, we should have exactly one of v and vector != NULL");
+
+    bool_t res = 0;
+
+    int    numElemInTheFile;
     if (list == NULL)
     {
         if (nval >= 0)
         {
-            if (nf != nval)
-            {
-                gmx_fatal(FARGS, "Count mismatch for state entry %s, code count is %d, file count is %d\n", st_names(cptp, ecpt), nval, nf);
-            }
+            GMX_RELEASE_ASSERT(nptr == NULL, "With nval>=0 we should have nptr==NULL");
+            numElemInTheFile = nval;
         }
         else
         {
-            *nptr = nf;
+            if (v != NULL)
+            {
+                GMX_RELEASE_ASSERT(nptr != NULL, "With nval<0 we should have nptr!=NULL");
+                // cppcheck-suppress nullPointer
+                numElemInTheFile = *nptr;
+            }
+            else
+            {
+                numElemInTheFile = vector->size();
+            }
         }
     }
-    dt  = dtc;
-    res = xdr_int(xd, &dt);
+    /* Read/write the vector element count */
+    res = xdr_int(xd, &numElemInTheFile);
     if (res == 0)
     {
         return -1;
     }
-    if (dt != dtc)
-    {
-        fprintf(stderr, "Precision mismatch for state entry %s, code precision is %s, file precision is %s\n",
-                st_names(cptp, ecpt), xdr_datatype_names[dtc],
-                xdr_datatype_names[dt]);
-    }
-    if (list || !(sflags & (1<<ecpt)))
+    /* Read/write the element data type */
+    gmx_constexpr int xdrTypeInTheCode = xdr_type<T>::value;
+    int               xdrTypeInTheFile = xdrTypeInTheCode;
+    res = xdr_int(xd, &xdrTypeInTheFile);
+    if (res == 0)
     {
-        snew(va, nf);
-        vp = va;
+        return -1;
     }
-    else
+
+    if (list == NULL && (sflags & (1 << ecpt)))
     {
-        if (*v == NULL)
+        if (nval >= 0)
         {
-            snew(*v, nf);
+            if (numElemInTheFile != nval)
+            {
+                gmx_fatal(FARGS, "Count mismatch for state entry %s, code count is %d, file count is %d\n", entryName(part, ecpt), nval, numElemInTheFile);
+            }
         }
-        vp = *v;
-    }
-    if (dt == xdr_datatype_float)
-    {
-        if (!useDouble)
+        else if (nptr != NULL)
         {
-            // This branch is not reached unless vp is already float *.
-            vf = reinterpret_cast<float *>(vp);
+            *nptr = numElemInTheFile;
         }
-        else
+
+        bool typesMatch = (xdrTypeInTheFile == xdrTypeInTheCode);
+        if (!typesMatch)
         {
-            snew(vf, nf);
+            char buf[STRLEN];
+            sprintf(buf, "mismatch for state entry %s, code precision is %s, file precision is %s",
+                    entryName(part, ecpt),
+                    xdr_datatype_names[xdrTypeInTheCode],
+                    xdr_datatype_names[xdrTypeInTheFile]);
+
+            /* Matchting int and real should never occur, but check anyhow */
+            if (xdrTypeInTheFile == xdr_datatype_int ||
+                xdrTypeInTheCode == xdr_datatype_int)
+            {
+                gmx_fatal(FARGS, "Type %s: incompatible checkpoint formats or corrupted checkpoint file.", buf);
+            }
+            fprintf(stderr, "Precision %s\n", buf);
         }
-        res = xdr_vector(xd, reinterpret_cast<char *>(vf), nf,
-                         static_cast<unsigned int>(sizeof(float)), (xdrproc_t)xdr_float);
-        if (res == 0)
+
+        T *vp;
+        if (v != NULL)
         {
-            return -1;
+            if (*v == NULL)
+            {
+                snew(*v, numElemInTheFile);
+            }
+            vp = *v;
         }
-        if (useDouble)
+        else
         {
-            for (i = 0; i < nf; i++)
+            /* This conditional ensures that we don't resize on write.
+             * In particular in the state where this code was written
+             * PaddedRVecVector has a size of numElemInThefile and we
+             * don't want to loose that padding here.
+             */
+            if (vector->size() < static_cast<unsigned int>(numElemInTheFile))
             {
-                vp[i] = vf[i];
+                vector->resize(numElemInTheFile);
             }
-            sfree(vf);
+            vp = vector->data();
         }
-    }
-    else
-    {
-        if (useDouble)
+
+        char *vChar;
+        if (typesMatch)
         {
-            // This branch is not reached unless vp is already double *.
-            // cppcheck-suppress invalidPointerCast
-            vd = reinterpret_cast<double *>(vp);
+            vChar = reinterpret_cast<char *>(vp);
         }
         else
         {
-            snew(vd, nf);
+            snew(vChar, numElemInTheFile*sizeOfXdrType(xdrTypeInTheFile));
         }
-        res = xdr_vector(xd, reinterpret_cast<char *>(vd), nf,
-                         static_cast<unsigned int>(sizeof(double)), (xdrproc_t)xdr_double);
+        res = xdr_vector(xd, vChar,
+                         numElemInTheFile, sizeOfXdrType(xdrTypeInTheFile),
+                         xdrProc(xdrTypeInTheFile));
         if (res == 0)
         {
             return -1;
         }
-        if (!useDouble)
-        {
-            for (i = 0; i < nf; i++)
-            {
-                vp[i] = vd[i];
-            }
-            sfree(vd);
-        }
-    }
 
-    if (list)
-    {
-        switch (erealtype)
+        if (!typesMatch)
         {
-            case ecprREAL:
-                pr_reals(list, 0, st_names(cptp, ecpt), vp, nf);
-                break;
-            case ecprRVEC:
-                pr_rvecs(list, 0, st_names(cptp, ecpt), (rvec *)vp, nf/3);
-                break;
-            default:
-                gmx_incons("Unknown checkpoint real type");
+            /* In the old code float-double conversion came for free.
+             * In the new code we still support it, mainly because
+             * the tip4p_continue regression test makes use of this.
+             * It's an open question if we do or don't want to allow this.
+             */
+            convertArrayRealPrecision(vChar, vp, numElemInTheFile);
+            sfree(vChar);
         }
     }
-    if (va)
+    else
     {
-        sfree(va);
+        res = listXdrVector(xd, part, ecpt, numElemInTheFile, xdrTypeInTheFile,
+                            list, cptElementType);
     }
 
     return 0;
 }
 
+//! \brief Read/Write an std::vector
+template <typename T>
+static int doVector(XDR *xd, StatePart part, int ecpt, int sflags,
+                    std::vector<T> *vector, FILE *list)
+{
+    return doVectorLow<T>(xd, part, ecpt, sflags, -1, NULL, NULL, vector, list, CptElementType::real);
+}
+
+//! \brief Read/Write an std::vector, on read checks the number of elements matches \p numElements
+template <typename T>
+static int doVector(XDR *xd, StatePart part, int ecpt, int sflags,
+                    int numElements, std::vector<T> *vector, FILE *list)
+{
+    return doVectorLow<T>(xd, part, ecpt, sflags, numElements, NULL, NULL, vector, list, CptElementType::real);
+}
+
+//! \brief Read/Write a PaddedRVecVector, on read checks the number of elements matches \p numElements
+static int doPaddedVector(XDR *xd, StatePart part, int ecpt, int sflags,
+                          int numElements, PaddedRVecVector *v, FILE *list)
+{
+    rvec *v_rvec;
+
+    if (list == NULL && (sflags & (1 << ecpt)))
+    {
+        /* We resize the vector here to avoid pointer reallocation in
+         * do_cpte_reals_low. Note the we allocate 1 element extra for SIMD.
+         */
+        v->resize(numElements + 1);
+        v_rvec = as_rvec_array(v->data());
+    }
+    else
+    {
+        v_rvec = NULL;
+    }
+
+    return doVectorLow<real>(xd, part, ecpt, sflags,
+                             numElements*DIM, NULL, (real **)(&v_rvec), NULL,
+                             list, CptElementType::real3);
+}
 
 /* This function stores n along with the reals for reading,
  * but on reading it assumes that n matches the value in the checkpoint file,
  * a fatal error is generated when this is not the case.
  */
-static int do_cpte_reals(XDR *xd, int cptp, int ecpt, int sflags,
+static int do_cpte_reals(XDR *xd, StatePart part, int ecpt, int sflags,
                          int n, real **v, FILE *list)
 {
-    return do_cpte_reals_low(xd, cptp, ecpt, sflags, n, NULL, v, list, ecprREAL);
+    return doVectorLow<real>(xd, part, ecpt, sflags, n, NULL, v, NULL, list, CptElementType::real);
 }
 
 /* This function does the same as do_cpte_reals,
  * except that on reading it ignores the passed value of *n
- * and stored the value read from the checkpoint file in *n.
+ * and stores the value read from the checkpoint file in *n.
  */
-static int do_cpte_n_reals(XDR *xd, int cptp, int ecpt, int sflags,
+static int do_cpte_n_reals(XDR *xd, StatePart part, int ecpt, int sflags,
                            int *n, real **v, FILE *list)
 {
-    return do_cpte_reals_low(xd, cptp, ecpt, sflags, -1, n, v, list, ecprREAL);
+    return doVectorLow<real>(xd, part, ecpt, sflags, -1, n, v, NULL, list, CptElementType::real);
 }
 
-static int do_cpte_real(XDR *xd, int cptp, int ecpt, int sflags,
+static int do_cpte_real(XDR *xd, StatePart part, int ecpt, int sflags,
                         real *r, FILE *list)
 {
-    return do_cpte_reals_low(xd, cptp, ecpt, sflags, 1, NULL, &r, list, ecprREAL);
+    return doVectorLow<real>(xd, part, ecpt, sflags, 1, NULL, &r, NULL, list, CptElementType::real);
 }
 
-static int do_cpte_ints(XDR *xd, int cptp, int ecpt, int sflags,
+static int do_cpte_ints(XDR *xd, StatePart part, int ecpt, int sflags,
                         int n, int **v, FILE *list)
 {
-    bool_t res = 0;
-    int    dtc = xdr_datatype_int;
-    int   *vp, *va = NULL;
-    int    nf, dt;
-
-    nf  = n;
-    res = xdr_int(xd, &nf);
-    if (res == 0)
-    {
-        return -1;
-    }
-    if (list == NULL && v != NULL && nf != n)
-    {
-        gmx_fatal(FARGS, "Count mismatch for state entry %s, code count is %d, file count is %d\n", st_names(cptp, ecpt), n, nf);
-    }
-    dt  = dtc;
-    res = xdr_int(xd, &dt);
-    if (res == 0)
-    {
-        return -1;
-    }
-    if (dt != dtc)
-    {
-        gmx_fatal(FARGS, "Type mismatch for state entry %s, code type is %s, file type is %s\n",
-                  st_names(cptp, ecpt), xdr_datatype_names[dtc],
-                  xdr_datatype_names[dt]);
-    }
-    if (list || !(sflags & (1<<ecpt)) || v == NULL)
-    {
-        snew(va, nf);
-        vp = va;
-    }
-    else
-    {
-        if (*v == NULL)
-        {
-            snew(*v, nf);
-        }
-        vp = *v;
-    }
-    res = xdr_vector(xd, reinterpret_cast<char *>(vp), nf,
-                     static_cast<unsigned int>(sizeof(int)), (xdrproc_t)xdr_int);
-    if (res == 0)
-    {
-        return -1;
-    }
-    if (list)
-    {
-        pr_ivec(list, 0, st_names(cptp, ecpt), vp, nf, TRUE);
-    }
-    if (va)
-    {
-        sfree(va);
-    }
-
-    return 0;
+    return doVectorLow<int>(xd, part, ecpt, sflags, n, NULL, v, NULL, list, CptElementType::integer);
 }
 
-static int do_cpte_int(XDR *xd, int cptp, int ecpt, int sflags,
+static int do_cpte_int(XDR *xd, StatePart part, int ecpt, int sflags,
                        int *i, FILE *list)
 {
-    return do_cpte_ints(xd, cptp, ecpt, sflags, 1, &i, list);
+    return do_cpte_ints(xd, part, ecpt, sflags, 1, &i, list);
 }
 
-static int do_cpte_doubles(XDR *xd, int cptp, int ecpt, int sflags,
+static int do_cpte_doubles(XDR *xd, StatePart part, int ecpt, int sflags,
                            int n, double **v, FILE *list)
 {
-    bool_t  res = 0;
-    int     dtc = xdr_datatype_double;
-    double *vp, *va = NULL;
-    int     nf, dt;
-
-    nf  = n;
-    res = xdr_int(xd, &nf);
-    if (res == 0)
-    {
-        return -1;
-    }
-    if (list == NULL && nf != n)
-    {
-        gmx_fatal(FARGS, "Count mismatch for state entry %s, code count is %d, file count is %d\n", st_names(cptp, ecpt), n, nf);
-    }
-    dt  = dtc;
-    res = xdr_int(xd, &dt);
-    if (res == 0)
-    {
-        return -1;
-    }
-    if (dt != dtc)
-    {
-        gmx_fatal(FARGS, "Precision mismatch for state entry %s, code precision is %s, file precision is %s\n",
-                  st_names(cptp, ecpt), xdr_datatype_names[dtc],
-                  xdr_datatype_names[dt]);
-    }
-    if (list || !(sflags & (1<<ecpt)))
-    {
-        snew(va, nf);
-        vp = va;
-    }
-    else
-    {
-        if (*v == NULL)
-        {
-            snew(*v, nf);
-        }
-        vp = *v;
-    }
-    res = xdr_vector(xd, reinterpret_cast<char *>(vp), nf,
-                     static_cast<unsigned int>(sizeof(double)), (xdrproc_t)xdr_double);
-    if (res == 0)
-    {
-        return -1;
-    }
-    if (list)
-    {
-        pr_doubles(list, 0, st_names(cptp, ecpt), vp, nf);
-    }
-    if (va)
-    {
-        sfree(va);
-    }
-
-    return 0;
+    return doVectorLow<double>(xd, part, ecpt, sflags, n, NULL, v, NULL, list, CptElementType::real);
 }
 
-static int do_cpte_double(XDR *xd, int cptp, int ecpt, int sflags,
+static int do_cpte_double(XDR *xd, StatePart part, int ecpt, int sflags,
                           double *r, FILE *list)
 {
-    return do_cpte_doubles(xd, cptp, ecpt, sflags, 1, &r, list);
+    return do_cpte_doubles(xd, part, ecpt, sflags, 1, &r, list);
 }
 
-
-static int do_cpte_rvecs(XDR *xd, int cptp, int ecpt, int sflags,
-                         int n, rvec **v, FILE *list)
-{
-    return do_cpte_reals_low(xd, cptp, ecpt, sflags,
-                             n*DIM, NULL, (real **)v, list, ecprRVEC);
-}
-
-static int do_cpte_matrix(XDR *xd, int cptp, int ecpt, int sflags,
+static int do_cpte_matrix(XDR *xd, StatePart part, int ecpt, int sflags,
                           matrix v, FILE *list)
 {
     real *vr;
     int   ret;
 
     vr  = &(v[0][0]);
-    ret = do_cpte_reals_low(xd, cptp, ecpt, sflags,
-                            DIM*DIM, NULL, &vr, NULL, ecprMATRIX);
+    ret = doVectorLow<real>(xd, part, ecpt, sflags,
+                            DIM*DIM, NULL, &vr, NULL, NULL, CptElementType::matrix3x3);
 
     if (list && ret == 0)
     {
-        pr_rvecs(list, 0, st_names(cptp, ecpt), v, DIM);
+        pr_rvecs(list, 0, entryName(part, ecpt), v, DIM);
     }
 
     return ret;
 }
 
 
-static int do_cpte_nmatrix(XDR *xd, int cptp, int ecpt, int sflags,
+static int do_cpte_nmatrix(XDR *xd, StatePart part, int ecpt, int sflags,
                            int n, real **v, FILE *list)
 {
     int   i;
@@ -659,10 +741,10 @@ static int do_cpte_nmatrix(XDR *xd, int cptp, int ecpt, int sflags,
     }
     for (i = 0; i < n; i++)
     {
-        reti = do_cpte_reals_low(xd, cptp, ecpt, sflags, n, NULL, &(v[i]), NULL, ecprREAL);
+        reti = doVectorLow<real>(xd, part, ecpt, sflags, n, NULL, &(v[i]), NULL, NULL, CptElementType::matrix3x3);
         if (list && reti == 0)
         {
-            sprintf(name, "%s[%d]", st_names(cptp, ecpt), i);
+            sprintf(name, "%s[%d]", entryName(part, ecpt), i);
             pr_reals(list, 0, name, v[i], n);
         }
         if (reti != 0)
@@ -673,7 +755,7 @@ static int do_cpte_nmatrix(XDR *xd, int cptp, int ecpt, int sflags,
     return ret;
 }
 
-static int do_cpte_matrices(XDR *xd, int cptp, int ecpt, int sflags,
+static int do_cpte_matrices(XDR *xd, StatePart part, int ecpt, int sflags,
                             int n, matrix **v, FILE *list)
 {
     bool_t  res = 0;
@@ -690,7 +772,7 @@ static int do_cpte_matrices(XDR *xd, int cptp, int ecpt, int sflags,
     }
     if (list == NULL && nf != n)
     {
-        gmx_fatal(FARGS, "Count mismatch for state entry %s, code count is %d, file count is %d\n", st_names(cptp, ecpt), n, nf);
+        gmx_fatal(FARGS, "Count mismatch for state entry %s, code count is %d, file count is %d\n", entryName(part, ecpt), n, nf);
     }
     if (list || !(sflags & (1<<ecpt)))
     {
@@ -716,8 +798,9 @@ static int do_cpte_matrices(XDR *xd, int cptp, int ecpt, int sflags,
             }
         }
     }
-    ret = do_cpte_reals_low(xd, cptp, ecpt, sflags,
-                            nf*DIM*DIM, NULL, &vr, NULL, ecprMATRIX);
+    ret = doVectorLow<real>(xd, part, ecpt, sflags,
+                            nf*DIM*DIM, NULL, &vr, NULL, NULL,
+                            CptElementType::matrix3x3);
     for (i = 0; i < nf; i++)
     {
         for (j = 0; j < DIM; j++)
@@ -734,7 +817,7 @@ static int do_cpte_matrices(XDR *xd, int cptp, int ecpt, int sflags,
     {
         for (i = 0; i < nf; i++)
         {
-            pr_rvecs(list, 0, st_names(cptp, ecpt), vp[i], DIM);
+            pr_rvecs(list, 0, entryName(part, ecpt), vp[i], DIM);
         }
     }
     if (va)
@@ -901,6 +984,10 @@ static void do_cpt_header(XDR *xd, gmx_bool bRead, int *file_version,
     {
         do_cpt_int_err(xd, "swap", eSwapCoords, list);
     }
+    else
+    {
+        *eSwapCoords = eswapNO;
+    }
 }
 
 static int do_cpt_footer(XDR *xd, int file_version)
@@ -925,60 +1012,51 @@ static int do_cpt_footer(XDR *xd, int file_version)
     return 0;
 }
 
-static int do_cpt_state(XDR *xd, gmx_bool bRead,
+static int do_cpt_state(XDR *xd,
                         int fflags, t_state *state,
                         FILE *list)
 {
-    int    sflags;
-    int    i;
-    int    ret;
-    int    nnht, nnhtp;
+    int             ret    = 0;
 
-    ret = 0;
-
-    nnht  = state->nhchainlength*state->ngtc;
-    nnhtp = state->nhchainlength*state->nnhpres;
-
-    if (bRead) /* we need to allocate space for dfhist if we are reading */
-    {
-        init_df_history(&state->dfhist, state->dfhist.nlambda);
-    }
+    const int       nnht   = state->nhchainlength*state->ngtc;
+    const int       nnhtp  = state->nhchainlength*state->nnhpres;
 
-    sflags = state->flags;
-    for (i = 0; (i < estNR && ret == 0); i++)
+    const StatePart part   = StatePart::microState;
+    const int       sflags = state->flags;
+    for (int i = 0; (i < estNR && ret == 0); i++)
     {
         if (fflags & (1<<i))
         {
             switch (i)
             {
-                case estLAMBDA:  ret      = do_cpte_reals(xd, cptpEST, i, sflags, efptNR, &(state->lambda), list); break;
-                case estFEPSTATE: ret     = do_cpte_int (xd, cptpEST, i, sflags, &state->fep_state, list); break;
-                case estBOX:     ret      = do_cpte_matrix(xd, cptpEST, i, sflags, state->box, list); break;
-                case estBOX_REL: ret      = do_cpte_matrix(xd, cptpEST, i, sflags, state->box_rel, list); break;
-                case estBOXV:    ret      = do_cpte_matrix(xd, cptpEST, i, sflags, state->boxv, list); break;
-                case estPRES_PREV: ret    = do_cpte_matrix(xd, cptpEST, i, sflags, state->pres_prev, list); break;
-                case estSVIR_PREV:  ret   = do_cpte_matrix(xd, cptpEST, i, sflags, state->svir_prev, list); break;
-                case estFVIR_PREV:  ret   = do_cpte_matrix(xd, cptpEST, i, sflags, state->fvir_prev, list); break;
-                case estNH_XI:   ret      = do_cpte_doubles(xd, cptpEST, i, sflags, nnht, &state->nosehoover_xi, list); break;
-                case estNH_VXI:  ret      = do_cpte_doubles(xd, cptpEST, i, sflags, nnht, &state->nosehoover_vxi, list); break;
-                case estNHPRES_XI:   ret  = do_cpte_doubles(xd, cptpEST, i, sflags, nnhtp, &state->nhpres_xi, list); break;
-                case estNHPRES_VXI:  ret  = do_cpte_doubles(xd, cptpEST, i, sflags, nnhtp, &state->nhpres_vxi, list); break;
-                case estTC_INT:  ret      = do_cpte_doubles(xd, cptpEST, i, sflags, state->ngtc, &state->therm_integral, list); break;
-                case estVETA:    ret      = do_cpte_real(xd, cptpEST, i, sflags, &state->veta, list); break;
-                case estVOL0:    ret      = do_cpte_real(xd, cptpEST, i, sflags, &state->vol0, list); break;
-                case estX:       ret      = do_cpte_rvecs(xd, cptpEST, i, sflags, state->natoms, &state->x, list); break;
-                case estV:       ret      = do_cpte_rvecs(xd, cptpEST, i, sflags, state->natoms, &state->v, list); break;
+                case estLAMBDA:  ret      = doVector<real>(xd, part, i, sflags, static_cast<int>(efptNR), &state->lambda, list); break;
+                case estFEPSTATE: ret     = do_cpte_int (xd, part, i, sflags, &state->fep_state, list); break;
+                case estBOX:     ret      = do_cpte_matrix(xd, part, i, sflags, state->box, list); break;
+                case estBOX_REL: ret      = do_cpte_matrix(xd, part, i, sflags, state->box_rel, list); break;
+                case estBOXV:    ret      = do_cpte_matrix(xd, part, i, sflags, state->boxv, list); break;
+                case estPRES_PREV: ret    = do_cpte_matrix(xd, part, i, sflags, state->pres_prev, list); break;
+                case estSVIR_PREV:  ret   = do_cpte_matrix(xd, part, i, sflags, state->svir_prev, list); break;
+                case estFVIR_PREV:  ret   = do_cpte_matrix(xd, part, i, sflags, state->fvir_prev, list); break;
+                case estNH_XI:   ret      = doVector<double>(xd, part, i, sflags, nnht, &state->nosehoover_xi, list); break;
+                case estNH_VXI:  ret      = doVector<double>(xd, part, i, sflags, nnht, &state->nosehoover_vxi, list); break;
+                case estNHPRES_XI:   ret  = doVector<double>(xd, part, i, sflags, nnhtp, &state->nhpres_xi, list); break;
+                case estNHPRES_VXI:  ret  = doVector<double>(xd, part, i, sflags, nnhtp, &state->nhpres_vxi, list); break;
+                case estTC_INT:  ret      = doVector<double>(xd, part, i, sflags, state->ngtc, &state->therm_integral, list); break;
+                case estVETA:    ret      = do_cpte_real(xd, part, i, sflags, &state->veta, list); break;
+                case estVOL0:    ret      = do_cpte_real(xd, part, i, sflags, &state->vol0, list); break;
+                case estX:       ret      = doPaddedVector(xd, part, i, sflags, state->natoms, &state->x, list); break;
+                case estV:       ret      = doPaddedVector(xd, part, i, sflags, state->natoms, &state->v, list); break;
                 /* The RNG entries are no longer written,
                  * the next 4 lines are only for reading old files.
                  */
-                case estLD_RNG:  ret      = do_cpte_ints(xd, cptpEST, i, sflags, 0, NULL, list); break;
-                case estLD_RNGI: ret      = do_cpte_ints(xd, cptpEST, i, sflags, 0, NULL, list); break;
-                case estMC_RNG:  ret      = do_cpte_ints(xd, cptpEST, i, sflags, 0, NULL, list); break;
-                case estMC_RNGI: ret      = do_cpte_ints(xd, cptpEST, i, sflags, 0, NULL, list); break;
-                case estDISRE_INITF:  ret = do_cpte_real (xd, cptpEST, i, sflags, &state->hist.disre_initf, list); break;
-                case estDISRE_RM3TAV: ret = do_cpte_n_reals(xd, cptpEST, i, sflags, &state->hist.ndisrepairs, &state->hist.disre_rm3tav, list); break;
-                case estORIRE_INITF:  ret = do_cpte_real (xd, cptpEST, i, sflags, &state->hist.orire_initf, list); break;
-                case estORIRE_DTAV:   ret = do_cpte_n_reals(xd, cptpEST, i, sflags, &state->hist.norire_Dtav, &state->hist.orire_Dtav, list); break;
+                case estLD_RNG:  ret      = do_cpte_ints(xd, part, i, sflags, 0, NULL, list); break;
+                case estLD_RNGI: ret      = do_cpte_ints(xd, part, i, sflags, 0, NULL, list); break;
+                case estMC_RNG:  ret      = do_cpte_ints(xd, part, i, sflags, 0, NULL, list); break;
+                case estMC_RNGI: ret      = do_cpte_ints(xd, part, i, sflags, 0, NULL, list); break;
+                case estDISRE_INITF:  ret = do_cpte_real (xd, part, i, sflags, &state->hist.disre_initf, list); break;
+                case estDISRE_RM3TAV: ret = do_cpte_n_reals(xd, part, i, sflags, &state->hist.ndisrepairs, &state->hist.disre_rm3tav, list); break;
+                case estORIRE_INITF:  ret = do_cpte_real (xd, part, i, sflags, &state->hist.orire_initf, list); break;
+                case estORIRE_DTAV:   ret = do_cpte_n_reals(xd, part, i, sflags, &state->hist.norire_Dtav, &state->hist.orire_Dtav, list); break;
                 default:
                     gmx_fatal(FARGS, "Unknown state entry %d\n"
                               "You are reading a checkpoint file written by different code, which is not supported", i);
@@ -992,28 +1070,26 @@ static int do_cpt_state(XDR *xd, gmx_bool bRead,
 static int do_cpt_ekinstate(XDR *xd, int fflags, ekinstate_t *ekins,
                             FILE *list)
 {
-    int  i;
-    int  ret;
+    int             ret  = 0;
 
-    ret = 0;
-
-    for (i = 0; (i < eeksNR && ret == 0); i++)
+    const StatePart part = StatePart::kineticEnergy;
+    for (int i = 0; (i < eeksNR && ret == 0); i++)
     {
         if (fflags & (1<<i))
         {
             switch (i)
             {
 
-                case eeksEKIN_N:     ret = do_cpte_int(xd, cptpEEKS, i, fflags, &ekins->ekin_n, list); break;
-                case eeksEKINH:     ret  = do_cpte_matrices(xd, cptpEEKS, i, fflags, ekins->ekin_n, &ekins->ekinh, list); break;
-                case eeksEKINF:      ret = do_cpte_matrices(xd, cptpEEKS, i, fflags, ekins->ekin_n, &ekins->ekinf, list); break;
-                case eeksEKINO:      ret = do_cpte_matrices(xd, cptpEEKS, i, fflags, ekins->ekin_n, &ekins->ekinh_old, list); break;
-                case eeksEKINTOTAL:  ret = do_cpte_matrix(xd, cptpEEKS, i, fflags, ekins->ekin_total, list); break;
-                case eeksEKINSCALEF: ret = do_cpte_doubles(xd, cptpEEKS, i, fflags, ekins->ekin_n, &ekins->ekinscalef_nhc, list); break;
-                case eeksVSCALE:     ret = do_cpte_doubles(xd, 1, cptpEEKS, fflags, ekins->ekin_n, &ekins->vscale_nhc, list); break;
-                case eeksEKINSCALEH: ret = do_cpte_doubles(xd, 1, cptpEEKS, fflags, ekins->ekin_n, &ekins->ekinscaleh_nhc, list); break;
-                case eeksDEKINDL:   ret  = do_cpte_real(xd, 1, cptpEEKS, fflags, &ekins->dekindl, list); break;
-                case eeksMVCOS:      ret = do_cpte_real(xd, 1, cptpEEKS, fflags, &ekins->mvcos, list); break;
+                case eeksEKIN_N:     ret = do_cpte_int(xd, part, i, fflags, &ekins->ekin_n, list); break;
+                case eeksEKINH:     ret  = do_cpte_matrices(xd, part, i, fflags, ekins->ekin_n, &ekins->ekinh, list); break;
+                case eeksEKINF:      ret = do_cpte_matrices(xd, part, i, fflags, ekins->ekin_n, &ekins->ekinf, list); break;
+                case eeksEKINO:      ret = do_cpte_matrices(xd, part, i, fflags, ekins->ekin_n, &ekins->ekinh_old, list); break;
+                case eeksEKINTOTAL:  ret = do_cpte_matrix(xd, part, i, fflags, ekins->ekin_total, list); break;
+                case eeksEKINSCALEF: ret = doVector<double>(xd, part, i, fflags, ekins->ekin_n, &ekins->ekinscalef_nhc, list); break;
+                case eeksVSCALE:     ret = doVector<double>(xd, part, i, fflags, ekins->ekin_n, &ekins->vscale_nhc, list); break;
+                case eeksEKINSCALEH: ret = doVector<double>(xd, part, i, fflags, ekins->ekin_n, &ekins->ekinscaleh_nhc, list); break;
+                case eeksDEKINDL:   ret  = do_cpte_real(xd, part, i, fflags, &ekins->dekindl, list); break;
+                case eeksMVCOS:      ret = do_cpte_real(xd, part, i, fflags, &ekins->mvcos, list); break;
                 default:
                     gmx_fatal(FARGS, "Unknown ekin data state entry %d\n"
                               "You are probably reading a new checkpoint file with old code", i);
@@ -1025,18 +1101,23 @@ static int do_cpt_ekinstate(XDR *xd, int fflags, ekinstate_t *ekins,
 }
 
 
-static int do_cpt_swapstate(XDR *xd, gmx_bool bRead, swapstate_t *swapstate, FILE *list)
+static int do_cpt_swapstate(XDR *xd, gmx_bool bRead,
+                            int eSwapCoords, swapstate_t **swapstatePtr, FILE *list)
 {
-    int ret              = 0;
     int swap_cpt_version = 2;
 
-
-    if (eswapNO == swapstate->eSwapCoords)
+    if (eSwapCoords == eswapNO)
     {
-        return ret;
+        return 0;
     }
 
-    swapstate->bFromCpt = bRead;
+    if (*swapstatePtr == NULL)
+    {
+        snew(*swapstatePtr, 1);
+    }
+    swapstate_t *swapstate = *swapstatePtr;
+    swapstate->bFromCpt    = bRead;
+    swapstate->eSwapCoords = eSwapCoords;
 
     do_cpt_int_err(xd, "swap checkpoint version", &swap_cpt_version, list);
     if (bRead && swap_cpt_version < 2)
@@ -1160,7 +1241,7 @@ static int do_cpt_swapstate(XDR *xd, gmx_bool bRead, swapstate_t *swapstate, FIL
         do_cpt_n_rvecs_err(xd, "Ch1 whole x", swapstate->nat[eChan1], *swapstate->xc_old_whole_p[eChan1], list);
     }
 
-    return ret;
+    return 0;
 }
 
 
@@ -1168,65 +1249,68 @@ static int do_cpt_enerhist(XDR *xd, gmx_bool bRead,
                            int fflags, energyhistory_t *enerhist,
                            FILE *list)
 {
-    int  i;
-    int  j;
-    int  ret;
-
-    ret = 0;
+    int ret = 0;
 
+    /* This is stored/read for backward compatibility */
+    int  energyHistoryNumEnergies = 0;
     if (bRead)
     {
         enerhist->nsteps     = 0;
         enerhist->nsum       = 0;
         enerhist->nsteps_sim = 0;
         enerhist->nsum_sim   = 0;
-        enerhist->dht        = NULL;
-
-        if (fflags & (1<< eenhENERGY_DELTA_H_NN) )
-        {
-            snew(enerhist->dht, 1);
-            enerhist->dht->ndh              = NULL;
-            enerhist->dht->dh               = NULL;
-            enerhist->dht->start_lambda_set = FALSE;
-        }
+    }
+    else
+    {
+        energyHistoryNumEnergies = enerhist->ener_sum_sim.size();
     }
 
-    for (i = 0; (i < eenhNR && ret == 0); i++)
+    delta_h_history_t *deltaH = enerhist->deltaHForeignLambdas.get();
+    const StatePart    part   = StatePart::energyHistory;
+    for (int i = 0; (i < eenhNR && ret == 0); i++)
     {
         if (fflags & (1<<i))
         {
             switch (i)
             {
-                case eenhENERGY_N:     ret = do_cpte_int(xd, cptpEENH, i, fflags, &enerhist->nener, list); break;
-                case eenhENERGY_AVER:  ret = do_cpte_doubles(xd, cptpEENH, i, fflags, enerhist->nener, &enerhist->ener_ave, list); break;
-                case eenhENERGY_SUM:   ret = do_cpte_doubles(xd, cptpEENH, i, fflags, enerhist->nener, &enerhist->ener_sum, list); break;
+                case eenhENERGY_N:     ret = do_cpte_int(xd, part, i, fflags, &energyHistoryNumEnergies, list); break;
+                case eenhENERGY_AVER:  ret = doVector<double>(xd, part, i, fflags, energyHistoryNumEnergies, &enerhist->ener_ave, list); break;
+                case eenhENERGY_SUM:   ret = doVector<double>(xd, part, i, fflags, energyHistoryNumEnergies, &enerhist->ener_sum, list); break;
                 case eenhENERGY_NSUM:  do_cpt_step_err(xd, eenh_names[i], &enerhist->nsum, list); break;
-                case eenhENERGY_SUM_SIM: ret = do_cpte_doubles(xd, cptpEENH, i, fflags, enerhist->nener, &enerhist->ener_sum_sim, list); break;
+                case eenhENERGY_SUM_SIM: ret = doVector<double>(xd, part, i, fflags, energyHistoryNumEnergies, &enerhist->ener_sum_sim, list); break;
                 case eenhENERGY_NSUM_SIM:   do_cpt_step_err(xd, eenh_names[i], &enerhist->nsum_sim, list); break;
                 case eenhENERGY_NSTEPS:     do_cpt_step_err(xd, eenh_names[i], &enerhist->nsteps, list); break;
                 case eenhENERGY_NSTEPS_SIM: do_cpt_step_err(xd, eenh_names[i], &enerhist->nsteps_sim, list); break;
-                case eenhENERGY_DELTA_H_NN: do_cpt_int_err(xd, eenh_names[i], &(enerhist->dht->nndh), list);
-                    if (bRead) /* now allocate memory for it */
+                case eenhENERGY_DELTA_H_NN:
+                {
+                    int numDeltaH = 0;
+                    if (!bRead && deltaH != nullptr)
+                    {
+                        numDeltaH = deltaH->dh.size();
+                    }
+                    do_cpt_int_err(xd, eenh_names[i], &numDeltaH, list);
+                    if (bRead)
                     {
-                        snew(enerhist->dht->dh, enerhist->dht->nndh);
-                        snew(enerhist->dht->ndh, enerhist->dht->nndh);
-                        for (j = 0; j < enerhist->dht->nndh; j++)
+                        if (deltaH == nullptr)
                         {
-                            enerhist->dht->ndh[j] = 0;
-                            enerhist->dht->dh[j]  = NULL;
+                            enerhist->deltaHForeignLambdas.reset(new delta_h_history_t);
+                            deltaH = enerhist->deltaHForeignLambdas.get();
                         }
+                        deltaH->dh.resize(numDeltaH);
+                        deltaH->start_lambda_set = FALSE;
                     }
                     break;
+                }
                 case eenhENERGY_DELTA_H_LIST:
-                    for (j = 0; j < enerhist->dht->nndh; j++)
+                    for (auto dh : deltaH->dh)
                     {
-                        ret = do_cpte_n_reals(xd, cptpEENH, i, fflags, &enerhist->dht->ndh[j], &(enerhist->dht->dh[j]), list);
+                        ret = doVector<real>(xd, part, i, fflags, &dh, list);
                     }
                     break;
                 case eenhENERGY_DELTA_H_STARTTIME:
-                    ret = do_cpte_double(xd, cptpEENH, i, fflags, &(enerhist->dht->start_time), list); break;
+                    ret = do_cpte_double(xd, part, i, fflags, &(deltaH->start_time), list); break;
                 case eenhENERGY_DELTA_H_STARTLAMBDA:
-                    ret = do_cpte_double(xd, cptpEENH, i, fflags, &(enerhist->dht->start_lambda), list); break;
+                    ret = do_cpte_double(xd, part, i, fflags, &(deltaH->start_lambda), list); break;
                 default:
                     gmx_fatal(FARGS, "Unknown energy history entry %d\n"
                               "You are probably reading a new checkpoint file with old code", i);
@@ -1237,11 +1321,7 @@ static int do_cpt_enerhist(XDR *xd, gmx_bool bRead,
     if ((fflags & (1<<eenhENERGY_SUM)) && !(fflags & (1<<eenhENERGY_SUM_SIM)))
     {
         /* Assume we have an old file format and copy sum to sum_sim */
-        srenew(enerhist->ener_sum_sim, enerhist->nener);
-        for (i = 0; i < enerhist->nener; i++)
-        {
-            enerhist->ener_sum_sim[i] = enerhist->ener_sum[i];
-        }
+        enerhist->ener_sum_sim = enerhist->ener_sum;
     }
 
     if ( (fflags & (1<<eenhENERGY_NSUM)) &&
@@ -1260,34 +1340,44 @@ static int do_cpt_enerhist(XDR *xd, gmx_bool bRead,
     return ret;
 }
 
-static int do_cpt_df_hist(XDR *xd, int fflags, df_history_t *dfhist, FILE *list)
+static int do_cpt_df_hist(XDR *xd, int fflags, int nlambda, df_history_t **dfhistPtr, FILE *list)
 {
-    int  i, nlambda;
-    int  ret;
+    int ret = 0;
+
+    if (fflags == 0)
+    {
+        return 0;
+    }
 
-    nlambda = dfhist->nlambda;
-    ret     = 0;
+    if (*dfhistPtr == NULL)
+    {
+        snew(*dfhistPtr, 1);
+        (*dfhistPtr)->nlambda = nlambda;
+        init_df_history(*dfhistPtr, nlambda);
+    }
+    df_history_t    *dfhist = *dfhistPtr;
 
-    for (i = 0; (i < edfhNR && ret == 0); i++)
+    const StatePart  part   = StatePart::freeEnergyHistory;
+    for (int i = 0; (i < edfhNR && ret == 0); i++)
     {
         if (fflags & (1<<i))
         {
             switch (i)
             {
-                case edfhBEQUIL:       ret = do_cpte_int(xd, cptpEDFH, i, fflags, &dfhist->bEquil, list); break;
-                case edfhNATLAMBDA:    ret = do_cpte_ints(xd, cptpEDFH, i, fflags, nlambda, &dfhist->n_at_lam, list); break;
-                case edfhWLHISTO:      ret = do_cpte_reals(xd, cptpEDFH, i, fflags, nlambda, &dfhist->wl_histo, list); break;
-                case edfhWLDELTA:      ret = do_cpte_real(xd, cptpEDFH, i, fflags, &dfhist->wl_delta, list); break;
-                case edfhSUMWEIGHTS:   ret = do_cpte_reals(xd, cptpEDFH, i, fflags, nlambda, &dfhist->sum_weights, list); break;
-                case edfhSUMDG:        ret = do_cpte_reals(xd, cptpEDFH, i, fflags, nlambda, &dfhist->sum_dg, list); break;
-                case edfhSUMMINVAR:    ret = do_cpte_reals(xd, cptpEDFH, i, fflags, nlambda, &dfhist->sum_minvar, list); break;
-                case edfhSUMVAR:       ret = do_cpte_reals(xd, cptpEDFH, i, fflags, nlambda, &dfhist->sum_variance, list); break;
-                case edfhACCUMP:       ret = do_cpte_nmatrix(xd, cptpEDFH, i, fflags, nlambda, dfhist->accum_p, list); break;
-                case edfhACCUMM:       ret = do_cpte_nmatrix(xd, cptpEDFH, i, fflags, nlambda, dfhist->accum_m, list); break;
-                case edfhACCUMP2:      ret = do_cpte_nmatrix(xd, cptpEDFH, i, fflags, nlambda, dfhist->accum_p2, list); break;
-                case edfhACCUMM2:      ret = do_cpte_nmatrix(xd, cptpEDFH, i, fflags, nlambda, dfhist->accum_m2, list); break;
-                case edfhTIJ:          ret = do_cpte_nmatrix(xd, cptpEDFH, i, fflags, nlambda, dfhist->Tij, list); break;
-                case edfhTIJEMP:       ret = do_cpte_nmatrix(xd, cptpEDFH, i, fflags, nlambda, dfhist->Tij_empirical, list); break;
+                case edfhBEQUIL:       ret = do_cpte_int(xd, part, i, fflags, &dfhist->bEquil, list); break;
+                case edfhNATLAMBDA:    ret = do_cpte_ints(xd, part, i, fflags, nlambda, &dfhist->n_at_lam, list); break;
+                case edfhWLHISTO:      ret = do_cpte_reals(xd, part, i, fflags, nlambda, &dfhist->wl_histo, list); break;
+                case edfhWLDELTA:      ret = do_cpte_real(xd, part, i, fflags, &dfhist->wl_delta, list); break;
+                case edfhSUMWEIGHTS:   ret = do_cpte_reals(xd, part, i, fflags, nlambda, &dfhist->sum_weights, list); break;
+                case edfhSUMDG:        ret = do_cpte_reals(xd, part, i, fflags, nlambda, &dfhist->sum_dg, list); break;
+                case edfhSUMMINVAR:    ret = do_cpte_reals(xd, part, i, fflags, nlambda, &dfhist->sum_minvar, list); break;
+                case edfhSUMVAR:       ret = do_cpte_reals(xd, part, i, fflags, nlambda, &dfhist->sum_variance, list); break;
+                case edfhACCUMP:       ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->accum_p, list); break;
+                case edfhACCUMM:       ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->accum_m, list); break;
+                case edfhACCUMP2:      ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->accum_p2, list); break;
+                case edfhACCUMM2:      ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->accum_m2, list); break;
+                case edfhTIJ:          ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->Tij, list); break;
+                case edfhTIJEMP:       ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->Tij_empirical, list); break;
 
                 default:
                     gmx_fatal(FARGS, "Unknown df history entry %d\n"
@@ -1304,19 +1394,21 @@ static int do_cpt_df_hist(XDR *xd, int fflags, df_history_t *dfhist, FILE *list)
  * average structure in the .cpt file
  */
 static int do_cpt_EDstate(XDR *xd, gmx_bool bRead,
-                          edsamstate_t *EDstate, FILE *list)
+                          int nED, edsamstate_t **EDstatePtr, FILE *list)
 {
-    int  i;
-    int  ret = 0;
-    char buf[STRLEN];
-
-
-    EDstate->bFromCpt = bRead;
+    if (nED == 0)
+    {
+        return 0;
+    }
 
-    if (EDstate->nED <= 0)
+    if (*EDstatePtr == NULL)
     {
-        return ret;
+        snew(*EDstatePtr, 1);
     }
+    edsamstate_t *EDstate = *EDstatePtr;
+
+    EDstate->bFromCpt     = bRead;
+    EDstate->nED          = nED;
 
     /* When reading, init_edsam has not been called yet,
      * so we have to allocate memory first. */
@@ -1329,8 +1421,10 @@ static int do_cpt_EDstate(XDR *xd, gmx_bool bRead,
     }
 
     /* Read/write the last whole conformation of SREF and SAV for each ED dataset (usually only one) */
-    for (i = 0; i < EDstate->nED; i++)
+    for (int i = 0; i < EDstate->nED; i++)
     {
+        char buf[STRLEN];
+
         /* Reference structure SREF */
         sprintf(buf, "ED%d # of atoms in reference structure", i+1);
         do_cpt_int_err(xd, buf, &EDstate->nref[i], list);
@@ -1360,7 +1454,7 @@ static int do_cpt_EDstate(XDR *xd, gmx_bool bRead,
         }
     }
 
-    return ret;
+    return 0;
 }
 
 
@@ -1460,7 +1554,8 @@ void write_checkpoint(const char *fn, gmx_bool bNumberAndKeep,
                       ivec domdecCells, int nppnodes,
                       int eIntegrator, int simulation_part,
                       gmx_bool bExpanded, int elamstats,
-                      gmx_int64_t step, double t, t_state *state)
+                      gmx_int64_t step, double t,
+                      t_state *state, energyhistory_t *enerhist)
 {
     t_fileio            *fp;
     int                  file_version;
@@ -1530,19 +1625,19 @@ void write_checkpoint(const char *fn, gmx_bool bNumberAndKeep,
     }
 
     flags_enh = 0;
-    if (state->enerhist->nsum > 0 || state->enerhist->nsum_sim > 0)
+    if (enerhist->nsum > 0 || enerhist->nsum_sim > 0)
     {
         flags_enh |= (1<<eenhENERGY_N) | (1<<eenhENERGY_NSTEPS) | (1<<eenhENERGY_NSTEPS_SIM);
-        if (state->enerhist->nsum > 0)
+        if (enerhist->nsum > 0)
         {
             flags_enh |= ((1<<eenhENERGY_AVER) | (1<<eenhENERGY_SUM) |
                           (1<<eenhENERGY_NSUM));
         }
-        if (state->enerhist->nsum_sim > 0)
+        if (enerhist->nsum_sim > 0)
         {
             flags_enh |= ((1<<eenhENERGY_SUM_SIM) | (1<<eenhENERGY_NSUM_SIM));
         }
-        if (state->enerhist->dht)
+        if (enerhist->deltaHForeignLambdas != nullptr)
         {
             flags_enh |= ( (1<< eenhENERGY_DELTA_H_NN) |
                            (1<< eenhENERGY_DELTA_H_LIST) |
@@ -1585,13 +1680,17 @@ void write_checkpoint(const char *fn, gmx_bool bNumberAndKeep,
 
     ftime   = &(timebuf[0]);
 
+    int nlambda     = (state->dfhist ? state->dfhist->nlambda : 0);
+    int nED         = (state->edsamstate ? state->edsamstate->nED : 0);
+    int eSwapCoords = (state->swapstate ? state->swapstate->eSwapCoords : eswapNO);
+
     do_cpt_header(gmx_fio_getxdr(fp), FALSE, &file_version,
                   &version, &btime, &buser, &bhost, &double_prec, &fprog, &ftime,
                   &eIntegrator, &simulation_part, &step, &t, &nppnodes,
                   DOMAINDECOMP(cr) ? domdecCells : NULL, &npmenodes,
                   &state->natoms, &state->ngtc, &state->nnhpres,
-                  &state->nhchainlength, &(state->dfhist.nlambda), &state->flags, &flags_eks, &flags_enh, &flags_dfh,
-                  &state->edsamstate.nED, &state->swapstate.eSwapCoords,
+                  &state->nhchainlength, &nlambda, &state->flags, &flags_eks, &flags_enh, &flags_dfh,
+                  &nED, &eSwapCoords,
                   NULL);
 
     sfree(version);
@@ -1600,12 +1699,12 @@ void write_checkpoint(const char *fn, gmx_bool bNumberAndKeep,
     sfree(bhost);
     sfree(fprog);
 
-    if ((do_cpt_state(gmx_fio_getxdr(fp), FALSE, state->flags, state, NULL) < 0)        ||
+    if ((do_cpt_state(gmx_fio_getxdr(fp), state->flags, state, NULL) < 0)        ||
         (do_cpt_ekinstate(gmx_fio_getxdr(fp), flags_eks, &state->ekinstate, NULL) < 0) ||
-        (do_cpt_enerhist(gmx_fio_getxdr(fp), FALSE, flags_enh, state->enerhist, NULL) < 0)  ||
-        (do_cpt_df_hist(gmx_fio_getxdr(fp), flags_dfh, &state->dfhist, NULL) < 0)  ||
-        (do_cpt_EDstate(gmx_fio_getxdr(fp), FALSE, &state->edsamstate, NULL) < 0)      ||
-        (do_cpt_swapstate(gmx_fio_getxdr(fp), FALSE, &state->swapstate, NULL) < 0) ||
+        (do_cpt_enerhist(gmx_fio_getxdr(fp), FALSE, flags_enh, enerhist, NULL) < 0)  ||
+        (do_cpt_df_hist(gmx_fio_getxdr(fp), flags_dfh, nlambda, &state->dfhist, NULL) < 0)  ||
+        (do_cpt_EDstate(gmx_fio_getxdr(fp), FALSE, nED, &state->edsamstate, NULL) < 0)      ||
+        (do_cpt_swapstate(gmx_fio_getxdr(fp), FALSE, eSwapCoords, &state->swapstate, NULL) < 0) ||
         (do_cpt_files(gmx_fio_getxdr(fp), FALSE, &outputfiles, &noutputfiles, NULL,
                       file_version) < 0))
     {
@@ -1849,6 +1948,7 @@ static void read_checkpoint(const char *fn, FILE **pfplog,
                             ivec dd_nc, int *npme,
                             int eIntegrator, int *init_fep_state, gmx_int64_t *step, double *t,
                             t_state *state, gmx_bool *bReadEkin,
+                            energyhistory_t *enerhist,
                             int *simulation_part,
                             gmx_bool bAppendOutputFiles, gmx_bool bForceAppend,
                             gmx_bool reproducibilityRequested)
@@ -1862,6 +1962,7 @@ static void read_checkpoint(const char *fn, FILE **pfplog,
     int                  eIntegrator_f, nppnodes_f, npmenodes_f;
     ivec                 dd_nc_f;
     int                  natoms, ngtc, nnhpres, nhchainlength, nlambda, fflags, flags_eks, flags_enh, flags_dfh;
+    int                  nED, eSwapCoords;
     int                  d;
     int                  ret;
     gmx_file_position_t *outputfiles;
@@ -1893,7 +1994,7 @@ static void read_checkpoint(const char *fn, FILE **pfplog,
                   &nppnodes_f, dd_nc_f, &npmenodes_f,
                   &natoms, &ngtc, &nnhpres, &nhchainlength, &nlambda,
                   &fflags, &flags_eks, &flags_enh, &flags_dfh,
-                  &state->edsamstate.nED, &state->swapstate.eSwapCoords, NULL);
+                  &nED, &eSwapCoords, NULL);
 
     if (bAppendOutputFiles &&
         file_version >= 13 && double_prec != GMX_DOUBLE)
@@ -1937,9 +2038,10 @@ static void read_checkpoint(const char *fn, FILE **pfplog,
         gmx_fatal(FARGS, "Checkpoint file is for a system of %d NH-pressure-coupling variables, while the current system consists of %d NH-pressure-coupling variables", nnhpres, state->nnhpres);
     }
 
-    if (nlambda != state->dfhist.nlambda)
+    int nlambdaHistory = (state->dfhist ? state->dfhist->nlambda : 0);
+    if (nlambda != nlambdaHistory)
     {
-        gmx_fatal(FARGS, "Checkpoint file is for a system with %d lambda states, while the current system consists of %d lambda states", nlambda, state->dfhist.nlambda);
+        gmx_fatal(FARGS, "Checkpoint file is for a system with %d lambda states, while the current system consists of %d lambda states", nlambda, nlambdaHistory);
     }
 
     init_gtc_state(state, state->ngtc, state->nnhpres, nhchainlength); /* need to keep this here to keep the tpr format working */
@@ -2026,7 +2128,7 @@ static void read_checkpoint(const char *fn, FILE **pfplog,
                         reproducibilityRequested);
         }
     }
-    ret             = do_cpt_state(gmx_fio_getxdr(fp), TRUE, fflags, state, NULL);
+    ret             = do_cpt_state(gmx_fio_getxdr(fp), fflags, state, NULL);
     *init_fep_state = state->fep_state;  /* there should be a better way to do this than setting it here.
                                             Investigate for 5.0. */
     if (ret)
@@ -2042,7 +2144,7 @@ static void read_checkpoint(const char *fn, FILE **pfplog,
                   ((flags_eks & (1<<eeksEKINSCALEF)) | (flags_eks & (1<<eeksEKINSCALEH)) | (flags_eks & (1<<eeksVSCALE))));
 
     ret = do_cpt_enerhist(gmx_fio_getxdr(fp), TRUE,
-                          flags_enh, state->enerhist, NULL);
+                          flags_enh, enerhist, NULL);
     if (ret)
     {
         cp_error();
@@ -2057,23 +2159,23 @@ static void read_checkpoint(const char *fn, FILE **pfplog,
         {
             fprintf(fplog, "\nWARNING: %s\n\n", warn);
         }
-        state->enerhist->nsum     = *step;
-        state->enerhist->nsum_sim = *step;
+        enerhist->nsum     = *step;
+        enerhist->nsum_sim = *step;
     }
 
-    ret = do_cpt_df_hist(gmx_fio_getxdr(fp), flags_dfh, &state->dfhist, NULL);
+    ret = do_cpt_df_hist(gmx_fio_getxdr(fp), flags_dfh, nlambda, &state->dfhist, NULL);
     if (ret)
     {
         cp_error();
     }
 
-    ret = do_cpt_EDstate(gmx_fio_getxdr(fp), TRUE, &state->edsamstate, NULL);
+    ret = do_cpt_EDstate(gmx_fio_getxdr(fp), TRUE, nED, &state->edsamstate, NULL);
     if (ret)
     {
         cp_error();
     }
 
-    ret = do_cpt_swapstate(gmx_fio_getxdr(fp), TRUE, &state->swapstate, NULL);
+    ret = do_cpt_swapstate(gmx_fio_getxdr(fp), TRUE, eSwapCoords, &state->swapstate, NULL);
     if (ret)
     {
         cp_error();
@@ -2249,6 +2351,7 @@ void load_checkpoint(const char *fn, FILE **fplog,
                      const t_commrec *cr, ivec dd_nc, int *npme,
                      t_inputrec *ir, t_state *state,
                      gmx_bool *bReadEkin,
+                     energyhistory_t *enerhist,
                      gmx_bool bAppend, gmx_bool bForceAppend,
                      gmx_bool reproducibilityRequested)
 {
@@ -2260,7 +2363,8 @@ void load_checkpoint(const char *fn, FILE **fplog,
         /* Read the state from the checkpoint file */
         read_checkpoint(fn, fplog,
                         cr, dd_nc, npme,
-                        ir->eI, &(ir->fepvals->init_fep_state), &step, &t, state, bReadEkin,
+                        ir->eI, &(ir->fepvals->init_fep_state), &step, &t,
+                        state, bReadEkin, enerhist,
                         &ir->simulation_part, bAppend, bForceAppend,
                         reproducibilityRequested);
     }
@@ -2290,9 +2394,11 @@ void read_checkpoint_part_and_step(const char  *filename,
     int       eIntegrator;
     int       nppnodes, npme;
     ivec      dd_nc;
+    int       nlambda;
     int       flags_eks, flags_enh, flags_dfh;
     double    t;
     t_state   state;
+    int       nED, eSwapCoords;
     t_fileio *fp;
 
     if (filename == NULL ||
@@ -2312,8 +2418,8 @@ void read_checkpoint_part_and_step(const char  *filename,
                   &version, &btime, &buser, &bhost, &double_prec, &fprog, &ftime,
                   &eIntegrator, simulation_part, step, &t, &nppnodes, dd_nc, &npme,
                   &state.natoms, &state.ngtc, &state.nnhpres, &state.nhchainlength,
-                  &(state.dfhist.nlambda), &state.flags, &flags_eks, &flags_enh, &flags_dfh,
-                  &state.edsamstate.nED, &state.swapstate.eSwapCoords, NULL);
+                  &nlambda, &state.flags, &flags_eks, &flags_enh, &flags_dfh,
+                  &nED, &eSwapCoords, NULL);
 
     gmx_fio_close(fp);
 }
@@ -2328,7 +2434,9 @@ static void read_checkpoint_data(t_fileio *fp, int *simulation_part,
     int                  eIntegrator;
     int                  nppnodes, npme;
     ivec                 dd_nc;
+    int                  nlambda;
     int                  flags_eks, flags_enh, flags_dfh;
+    int                  nED, eSwapCoords;
     int                  nfiles_loc;
     gmx_file_position_t *files_loc = NULL;
     int                  ret;
@@ -2337,10 +2445,10 @@ static void read_checkpoint_data(t_fileio *fp, int *simulation_part,
                   &version, &btime, &buser, &bhost, &double_prec, &fprog, &ftime,
                   &eIntegrator, simulation_part, step, t, &nppnodes, dd_nc, &npme,
                   &state->natoms, &state->ngtc, &state->nnhpres, &state->nhchainlength,
-                  &(state->dfhist.nlambda), &state->flags, &flags_eks, &flags_enh, &flags_dfh,
-                  &state->edsamstate.nED, &state->swapstate.eSwapCoords, NULL);
+                  &nlambda, &state->flags, &flags_eks, &flags_enh, &flags_dfh,
+                  &nED, &eSwapCoords, NULL);
     ret =
-        do_cpt_state(gmx_fio_getxdr(fp), TRUE, state->flags, state, NULL);
+        do_cpt_state(gmx_fio_getxdr(fp), state->flags, state, NULL);
     if (ret)
     {
         cp_error();
@@ -2350,25 +2458,27 @@ static void read_checkpoint_data(t_fileio *fp, int *simulation_part,
     {
         cp_error();
     }
+
+    energyhistory_t enerhist;
     ret = do_cpt_enerhist(gmx_fio_getxdr(fp), TRUE,
-                          flags_enh, state->enerhist, NULL);
+                          flags_enh, &enerhist, NULL);
     if (ret)
     {
         cp_error();
     }
-    ret = do_cpt_df_hist(gmx_fio_getxdr(fp), flags_dfh, &state->dfhist, NULL);
+    ret = do_cpt_df_hist(gmx_fio_getxdr(fp), flags_dfh, nlambda, &state->dfhist, NULL);
     if (ret)
     {
         cp_error();
     }
 
-    ret = do_cpt_EDstate(gmx_fio_getxdr(fp), TRUE, &state->edsamstate, NULL);
+    ret = do_cpt_EDstate(gmx_fio_getxdr(fp), TRUE, nED, &state->edsamstate, NULL);
     if (ret)
     {
         cp_error();
     }
 
-    ret = do_cpt_swapstate(gmx_fio_getxdr(fp), TRUE, &state->swapstate, NULL);
+    ret = do_cpt_swapstate(gmx_fio_getxdr(fp), TRUE, eSwapCoords, &state->swapstate, NULL);
     if (ret)
     {
         cp_error();
@@ -2452,14 +2562,12 @@ void read_checkpoint_trxframe(t_fileio *fp, t_trxframe *fr)
     fr->bX         = (state.flags & (1<<estX));
     if (fr->bX)
     {
-        fr->x     = state.x;
-        state.x   = NULL;
+        fr->x   = getRvecArrayFromPaddedRVecVector(&state.x, state.natoms);
     }
     fr->bV      = (state.flags & (1<<estV));
     if (fr->bV)
     {
-        fr->v     = state.v;
-        state.v   = NULL;
+        fr->v   = getRvecArrayFromPaddedRVecVector(&state.v, state.natoms);
     }
     fr->bF      = FALSE;
     fr->bBox    = (state.flags & (1<<estBOX));
@@ -2467,7 +2575,6 @@ void read_checkpoint_trxframe(t_fileio *fp, t_trxframe *fr)
     {
         copy_mat(state.box, fr->box);
     }
-    done_state(&state);
 }
 
 void list_checkpoint(const char *fn, FILE *out)
@@ -2480,23 +2587,25 @@ void list_checkpoint(const char *fn, FILE *out)
     gmx_int64_t          step;
     double               t;
     ivec                 dd_nc;
-    t_state              state;
+    int                  nlambda;
     int                  flags_eks, flags_enh, flags_dfh;
+    int                  nED, eSwapCoords;
     int                  ret;
     gmx_file_position_t *outputfiles;
     int                  nfiles;
 
-    init_state(&state, -1, -1, -1, -1, 0);
+    t_state              state = {};
+    init_state(&state, 0, 0, 0, 0, 0);
 
     fp = gmx_fio_open(fn, "r");
     do_cpt_header(gmx_fio_getxdr(fp), TRUE, &file_version,
                   &version, &btime, &buser, &bhost, &double_prec, &fprog, &ftime,
                   &eIntegrator, &simulation_part, &step, &t, &nppnodes, dd_nc, &npme,
                   &state.natoms, &state.ngtc, &state.nnhpres, &state.nhchainlength,
-                  &(state.dfhist.nlambda), &state.flags,
-                  &flags_eks, &flags_enh, &flags_dfh, &state.edsamstate.nED,
-                  &state.swapstate.eSwapCoords, out);
-    ret = do_cpt_state(gmx_fio_getxdr(fp), TRUE, state.flags, &state, out);
+                  &nlambda, &state.flags,
+                  &flags_eks, &flags_enh, &flags_dfh, &nED, &eSwapCoords,
+                  out);
+    ret = do_cpt_state(gmx_fio_getxdr(fp), state.flags, &state, out);
     if (ret)
     {
         cp_error();
@@ -2506,23 +2615,25 @@ void list_checkpoint(const char *fn, FILE *out)
     {
         cp_error();
     }
+
+    energyhistory_t enerhist;
     ret = do_cpt_enerhist(gmx_fio_getxdr(fp), TRUE,
-                          flags_enh, state.enerhist, out);
+                          flags_enh, &enerhist, out);
 
     if (ret == 0)
     {
         ret = do_cpt_df_hist(gmx_fio_getxdr(fp),
-                             flags_dfh, &state.dfhist, out);
+                             flags_dfh, nlambda, &state.dfhist, out);
     }
 
     if (ret == 0)
     {
-        ret = do_cpt_EDstate(gmx_fio_getxdr(fp), TRUE, &state.edsamstate, out);
+        ret = do_cpt_EDstate(gmx_fio_getxdr(fp), TRUE, nED, &state.edsamstate, out);
     }
 
     if (ret == 0)
     {
-        ret = do_cpt_swapstate(gmx_fio_getxdr(fp), TRUE, &state.swapstate, out);
+        ret = do_cpt_swapstate(gmx_fio_getxdr(fp), TRUE, eSwapCoords, &state.swapstate, out);
     }
 
     if (ret == 0)
@@ -2543,8 +2654,6 @@ void list_checkpoint(const char *fn, FILE *out)
     {
         gmx_file("Cannot read/write checkpoint; corrupt file, or maybe you are out of disk space?");
     }
-
-    done_state(&state);
 }
 
 /* This routine cannot print tons of data, since it is called before the log file is opened. */
@@ -2566,5 +2675,4 @@ read_checkpoint_simulation_part_and_filenames(t_fileio             *fp,
     {
         gmx_file("Cannot read/write checkpoint; corrupt file, or maybe you are out of disk space?");
     }
-    done_state(&state);
 }
index 22f4d5cf5bac9b812e5bb6bebbb5fe1507d99eee..1da65e2a13c3c49d13dfb559fa22eaef3882e2ea 100644 (file)
@@ -47,6 +47,7 @@
 extern "C" {
 #endif
 
+class energyhistory_t;
 struct gmx_file_position_t;
 struct t_commrec;
 struct t_fileio;
@@ -67,7 +68,7 @@ void write_checkpoint(const char *fn, gmx_bool bNumberAndKeep,
                       int eIntegrator, int simulation_part,
                       gmx_bool bExpanded, int elamstats,
                       gmx_int64_t step, double t,
-                      t_state *state);
+                      t_state *state, energyhistory_t *enerhist);
 
 /* Loads a checkpoint from fn for run continuation.
  * Generates a fatal error on system size mismatch.
@@ -84,6 +85,7 @@ void load_checkpoint(const char *fn, FILE **fplog,
                      const t_commrec *cr, ivec dd_nc, int *npme,
                      t_inputrec *ir, t_state *state,
                      gmx_bool *bReadEkin,
+                     energyhistory_t *enerhist,
                      gmx_bool bAppend, gmx_bool bForceAppend,
                      gmx_bool reproducibilityRequested);
 
index a370d48890df143cacf5fde6a60ff4445b478b55..7735957498427c434613cdfc4ffe885eeab2c416 100644 (file)
@@ -50,7 +50,6 @@
 #include "gromacs/fileio/tpxio.h"
 #include "gromacs/fileio/trxio.h"
 #include "gromacs/math/vec.h"
-#include "gromacs/topology/atomprop.h"
 #include "gromacs/topology/atoms.h"
 #include "gromacs/topology/block.h"
 #include "gromacs/topology/mtop_util.h"
@@ -59,6 +58,7 @@
 #include "gromacs/trajectory/trajectoryframe.h"
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/smalloc.h"
 
 void write_sto_conf_indexed(const char *outfile, const char *title,
@@ -304,7 +304,8 @@ static void tpx_make_chain_identifiers(t_atoms *atoms, t_block *mols)
     }
 }
 
-static void read_stx_conf(const char *infile, t_topology *top,
+static void read_stx_conf(const char *infile,
+                          t_symtab *symtab, char ***name, t_atoms *atoms,
                           rvec x[], rvec *v, int *ePBC, matrix box)
 {
     FILE       *in;
@@ -312,11 +313,11 @@ static void read_stx_conf(const char *infile, t_topology *top,
     int         ftp;
     char        g96_line[STRLEN+1];
 
-    if (top->atoms.nr == 0)
+    if (atoms->nr == 0)
     {
         fprintf(stderr, "Warning: Number of atoms in %s is 0\n", infile);
     }
-    else if (top->atoms.atom == NULL)
+    else if (atoms->atom == NULL)
     {
         gmx_mem("Uninitialized array atom");
     }
@@ -330,72 +331,82 @@ static void read_stx_conf(const char *infile, t_topology *top,
     switch (ftp)
     {
         case efGRO:
-            gmx_gro_read_conf(infile, top, x, v, box);
+            gmx_gro_read_conf(infile, symtab, name, atoms, x, v, box);
             break;
         case efG96:
             fr.title  = NULL;
-            fr.natoms = top->atoms.nr;
-            fr.atoms  = &top->atoms;
+            fr.natoms = atoms->nr;
+            fr.atoms  = atoms;
             fr.x      = x;
             fr.v      = v;
             fr.f      = NULL;
             in        = gmx_fio_fopen(infile, "r");
-            read_g96_conf(in, infile, &fr, &top->symtab, g96_line);
+            read_g96_conf(in, infile, &fr, symtab, g96_line);
             gmx_fio_fclose(in);
             copy_mat(fr.box, box);
-            top->name = put_symtab(&top->symtab, fr.title);
+            *name     = put_symtab(symtab, fr.title);
             sfree(const_cast<char *>(fr.title));
             break;
         case efPDB:
         case efBRK:
         case efENT:
-            gmx_pdb_read_conf(infile, top, x, ePBC, box);
+            gmx_pdb_read_conf(infile, symtab, name, atoms, x, ePBC, box);
             break;
         case efESP:
-            gmx_espresso_read_conf(infile, top, x, v, box);
+            gmx_espresso_read_conf(infile, symtab, name, atoms, x, v, box);
             break;
         default:
             gmx_incons("Not supported in read_stx_conf");
     }
 }
 
-static void done_gmx_groups_t(gmx_groups_t *g)
+static void readConfAndAtoms(const char *infile,
+                             t_symtab *symtab, char ***name, t_atoms *atoms,
+                             int *ePBC,
+                             rvec **x, rvec **v, matrix box)
 {
-    int i;
+    int natoms;
+    get_stx_coordnum(infile, &natoms);
+
+    init_t_atoms(atoms, natoms, (fn2ftp(infile) == efPDB));
 
-    for (i = 0; (i < egcNR); i++)
+    bool xIsNull = false;
+    if (x == NULL)
     {
-        if (NULL != g->grps[i].nm_ind)
-        {
-            sfree(g->grps[i].nm_ind);
-            g->grps[i].nm_ind = NULL;
-        }
-        if (NULL != g->grpnr[i])
-        {
-            sfree(g->grpnr[i]);
-            g->grpnr[i] = NULL;
-        }
+        snew(x, 1);
+        xIsNull = true;
+    }
+    snew(*x, natoms);
+    if (v)
+    {
+        snew(*v, natoms);
+    }
+    read_stx_conf(infile,
+                  symtab, name, atoms,
+                  *x, (v == NULL) ? NULL : *v, ePBC, box);
+    if (xIsNull)
+    {
+        sfree(*x);
+        sfree(x);
     }
-    /* The contents of this array is in symtab, don't free it here */
-    sfree(g->grpname);
 }
 
-gmx_bool read_tps_conf(const char *infile, t_topology *top, int *ePBC,
-                       rvec **x, rvec **v, matrix box, gmx_bool bMass)
+void readConfAndTopology(const char *infile,
+                         bool *haveTopology, gmx_mtop_t *mtop,
+                         int *ePBC,
+                         rvec **x, rvec **v, matrix box)
 {
-    t_tpxheader      header;
-    int              natoms, i;
-    gmx_bool         bTop, bXNULL = FALSE;
-    gmx_mtop_t      *mtop;
-    gmx_atomprop_t   aps;
+    GMX_RELEASE_ASSERT(mtop != NULL, "readConfAndTopology requires mtop!=NULL");
 
-    bTop  = fn2bTPX(infile);
     if (ePBC != NULL)
     {
         *ePBC = -1;
     }
-    if (bTop)
+
+    *haveTopology = fn2bTPX(infile);
+    if (*haveTopology)
     {
+        t_tpxheader header;
         read_tpxheader(infile, &header, TRUE);
         if (x)
         {
@@ -405,7 +416,7 @@ gmx_bool read_tps_conf(const char *infile, t_topology *top, int *ePBC,
         {
             snew(*v, header.natoms);
         }
-        snew(mtop, 1);
+        int natoms;
         int ePBC_tmp
             = read_tpx(infile, NULL, box, &natoms,
                        (x == NULL) ? NULL : *x, (v == NULL) ? NULL : *v, mtop);
@@ -413,56 +424,46 @@ gmx_bool read_tps_conf(const char *infile, t_topology *top, int *ePBC,
         {
             *ePBC = ePBC_tmp;
         }
-        *top = gmx_mtop_t_to_t_topology(mtop);
-        /* In this case we need to throw away the group data too */
-        done_gmx_groups_t(&mtop->groups);
-        sfree(mtop);
-        tpx_make_chain_identifiers(&top->atoms, &top->mols);
     }
     else
     {
-        open_symtab(&top->symtab);
-        get_stx_coordnum(infile, &natoms);
-        init_t_atoms(&top->atoms, natoms, (fn2ftp(infile) == efPDB));
-        if (x == NULL)
-        {
-            snew(x, 1);
-            bXNULL = TRUE;
-        }
-        snew(*x, natoms);
-        if (v)
-        {
-            snew(*v, natoms);
-        }
-        read_stx_conf(infile, top, *x, (v == NULL) ? NULL : *v, ePBC, box);
-        if (bXNULL)
-        {
-            sfree(*x);
-            sfree(x);
-        }
-        if (bMass)
+        t_symtab   symtab;
+        char     **name;
+        t_atoms    atoms;
+
+        open_symtab(&symtab);
+
+        readConfAndAtoms(infile, &symtab, &name, &atoms, ePBC, x, v, box);
+
+        init_mtop(mtop);
+        convertAtomsToMtop(&symtab, name, &atoms, mtop);
+    }
+}
+
+gmx_bool read_tps_conf(const char *infile, t_topology *top, int *ePBC,
+                       rvec **x, rvec **v, matrix box, gmx_bool requireMasses)
+{
+    bool        haveTopology;
+    gmx_mtop_t *mtop;
+
+    // Note: We should have an initializer instead of relying on snew
+    snew(mtop, 1);
+    readConfAndTopology(infile, &haveTopology, mtop, ePBC, x, v, box);
+
+    *top = gmx_mtop_t_to_t_topology(mtop, true);
+    sfree(mtop);
+
+    tpx_make_chain_identifiers(&top->atoms, &top->mols);
+
+    if (requireMasses && !top->atoms.haveMass)
+    {
+        atomsSetMassesBasedOnNames(&top->atoms, TRUE);
+
+        if (!top->atoms.haveMass)
         {
-            aps = gmx_atomprop_init();
-            for (i = 0; (i < natoms); i++)
-            {
-                if (!gmx_atomprop_query(aps, epropMass,
-                                        *top->atoms.resinfo[top->atoms.atom[i].resind].name,
-                                        *top->atoms.atomname[i],
-                                        &(top->atoms.atom[i].m)))
-                {
-                    if (debug)
-                    {
-                        fprintf(debug, "Can not find mass for atom %s %d %s, setting to 1\n",
-                                *top->atoms.resinfo[top->atoms.atom[i].resind].name,
-                                top->atoms.resinfo[top->atoms.atom[i].resind].nr,
-                                *top->atoms.atomname[i]);
-                    }
-                }
-            }
-            gmx_atomprop_destroy(aps);
+            gmx_fatal(FARGS, "Masses were requested, but for some atom(s) masses could not be found in the database. Use a tpr file as input, if possible, or add these atoms to the mass database.");
         }
-        top->idef.ntypes = -1;
     }
 
-    return bTop;
+    return haveTopology;
 }
index 459c7167cea0952a77218907606b96e589ca7261..18fe339aa468efdcc2c5b4fde5448752213a4bac 100644 (file)
@@ -68,14 +68,46 @@ void write_sto_conf_mtop(const char *outfile, const char *title,
                          const rvec x[], const rvec *v, int ePBC, const matrix box);
 /* As write_sto_conf, but uses a gmx_mtop_t struct */
 
-gmx_bool read_tps_conf(const char *infile, struct t_topology *top,
-                       int *ePBC, rvec **x, rvec **v, matrix box, gmx_bool bMass);
-/* Read title, top.atoms, x, v (if not NULL) and box from an STX file,
- * memory for atoms, x and v will be allocated.
- * Return TRUE if a complete topology was read.
- * If infile is a TPX file read the whole top,
- * else if bMass=TRUE, read the masses into top.atoms from the mass database.
+/*! \brief Read a configuration and, when available, a topology from a tpr or structure file.
+ *
+ * When reading from a tpr file, the complete topology is returned in \p mtop.
+ * When reading from a structure file, only the atoms struct in \p mtop contains data.
+ *
+ * \param[in]     infile        Input file name
+ * \param[out]    haveTopology  true when a topology was read and stored in mtop
+ * \param[out]    mtop          The topology, either complete or only atom data
+ * \param[out]    ePBC          Enum reporting the type of PBC
+ * \param[in,out] x             Coordinates will be stored when *x!=NULL
+ * \param[in,out] v             Velocities will be stored when *v!=NULL
+ * \param[out]    box           Box dimensions
+ */
+void readConfAndTopology(const char *infile,
+                         bool *haveTopology, gmx_mtop_t *mtop,
+                         int *ePBC,
+                         rvec **x, rvec **v, matrix box);
+
+/*! \brief Read a configuration and, when available, a topology from a tpr or structure file.
+ *
+ * Deprecated, superseded by readConfAndTopology().
+ * When \p requireMasses = TRUE, this routine must return a topology with
+ * mass data. Masses are either read from a tpr input file, or otherwise
+ * looked up from the mass database, and when such lookup fails a fatal error
+ * results.
+ * When \p requireMasses = FALSE, masses will still be read from tpr input and
+ * their presence is signaled with the \p haveMass flag in t_atoms of \p top.
+ *
+ * \param[in]     infile        Input file name
+ * \param[out]    top           The topology, either complete or only atom data
+ * \param[out]    ePBC          Enum reporting the type of PBC
+ * \param[in,out] x             Coordinates will be stored when *x!=NULL
+ * \param[in,out] v             Velocities will be stored when *v!=NULL
+ * \param[out]    box           Box dimensions
+ * \param[in]     requireMasses Require masses to be present, either from tpr or from the mass database
+ * \returns if a topology is available
  */
+gmx_bool read_tps_conf(const char *infile, struct t_topology *top,
+                       int *ePBC, rvec **x, rvec **v, matrix box,
+                       gmx_bool requireMasses);
 
 #ifdef __cplusplus
 }
index 48d4b7bc98f197a227ba369b5104ab4706e765f7..6dc3619ffc4ba516a5d942e2f0bde3d98b75189c 100644 (file)
@@ -52,6 +52,7 @@
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/topology/topology.h"
+#include "gromacs/utility/compare.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/futil.h"
 #include "gromacs/utility/gmxassert.h"
@@ -251,8 +252,6 @@ void init_enxframe(t_enxframe *fr)
     fr->ener    = NULL;
 
     /*fr->d_alloc=0;*/
-    fr->ener = NULL;
-
     /*fr->ndisre=0;*/
 
     fr->nblock       = 0;
@@ -497,6 +496,7 @@ static gmx_bool do_eheader(ener_file_t ef, int *file_version, t_enxframe *fr,
             return FALSE;
         }
         *file_version = enx_version;
+        // cppcheck-suppress redundantPointerOp
         if (!gmx_fio_do_int(ef->fio, *file_version))
         {
             *bOK = FALSE;
@@ -1246,3 +1246,364 @@ void get_enx_state(const char *fn, real t, const gmx_groups_t *groups, t_inputre
     free_enxframe(fr);
     sfree(fr);
 }
+
+static real ener_tensor_diag(int n, int *ind1, int *ind2,
+                             gmx_enxnm_t *enm1,
+                             int *tensi, int i,
+                             t_energy e1[], t_energy e2[])
+{
+    int    d1, d2;
+    int    j;
+    real   prod1, prod2;
+    int    nfound;
+    size_t len;
+
+    d1 = tensi[i]/DIM;
+    d2 = tensi[i] - d1*DIM;
+
+    /* Find the diagonal elements d1 and d2 */
+    len    = std::strlen(enm1[ind1[i]].name);
+    prod1  = 1;
+    prod2  = 1;
+    nfound = 0;
+    for (j = 0; j < n; j++)
+    {
+        if (tensi[j] >= 0 &&
+            std::strlen(enm1[ind1[j]].name) == len &&
+            std::strncmp(enm1[ind1[i]].name, enm1[ind1[j]].name, len-2) == 0 &&
+            (tensi[j] == d1*DIM+d1 || tensi[j] == d2*DIM+d2))
+        {
+            prod1 *= fabs(e1[ind1[j]].e);
+            prod2 *= fabs(e2[ind2[j]].e);
+            nfound++;
+        }
+    }
+
+    if (nfound == 2)
+    {
+        return 0.5*(std::sqrt(prod1) + std::sqrt(prod2));
+    }
+    else
+    {
+        return 0;
+    }
+}
+
+static gmx_bool enernm_equal(const char *nm1, const char *nm2)
+{
+    int len1, len2;
+
+    len1 = std::strlen(nm1);
+    len2 = std::strlen(nm2);
+
+    /* Remove " (bar)" at the end of a name */
+    if (len1 > 6 && std::strcmp(nm1+len1-6, " (bar)") == 0)
+    {
+        len1 -= 6;
+    }
+    if (len2 > 6 && std::strcmp(nm2+len2-6, " (bar)") == 0)
+    {
+        len2 -= 6;
+    }
+
+    return (len1 == len2 && gmx_strncasecmp(nm1, nm2, len1) == 0);
+}
+
+static void cmp_energies(FILE *fp, int step1, int step2,
+                         t_energy e1[], t_energy e2[],
+                         gmx_enxnm_t *enm1,
+                         real ftol, real abstol,
+                         int nre, int *ind1, int *ind2, int maxener)
+{
+    int   i, ii;
+    int  *tensi, len, d1, d2;
+    real  ftol_i, abstol_i;
+
+    snew(tensi, maxener);
+    /* Check for tensor elements ending on "-XX", "-XY", ... , "-ZZ" */
+    for (i = 0; (i < maxener); i++)
+    {
+        ii       = ind1[i];
+        tensi[i] = -1;
+        len      = std::strlen(enm1[ii].name);
+        if (len > 3 && enm1[ii].name[len-3] == '-')
+        {
+            d1 = enm1[ii].name[len-2] - 'X';
+            d2 = enm1[ii].name[len-1] - 'X';
+            if (d1 >= 0 && d1 < DIM &&
+                d2 >= 0 && d2 < DIM)
+            {
+                tensi[i] = d1*DIM + d2;
+            }
+        }
+    }
+
+    for (i = 0; (i < maxener); i++)
+    {
+        /* Check if this is an off-diagonal tensor element */
+        if (tensi[i] >= 0 && tensi[i] != 0 && tensi[i] != 4 && tensi[i] != 8)
+        {
+            /* Turn on the relative tolerance check (4 is maximum relative diff.) */
+            ftol_i = 5;
+            /* Do the relative tolerance through an absolute tolerance times
+             * the size of diagonal components of the tensor.
+             */
+            abstol_i = ftol*ener_tensor_diag(nre, ind1, ind2, enm1, tensi, i, e1, e2);
+            if (debug)
+            {
+                fprintf(debug, "tensor '%s' val %f diag %f\n",
+                        enm1[i].name, e1[i].e, abstol_i/ftol);
+            }
+            if (abstol_i > 0)
+            {
+                /* We found a diagonal, we need to check with the minimum tolerance */
+                abstol_i = std::min(abstol_i, abstol);
+            }
+            else
+            {
+                /* We did not find a diagonal, ignore the relative tolerance check */
+                abstol_i = abstol;
+            }
+        }
+        else
+        {
+            ftol_i   = ftol;
+            abstol_i = abstol;
+        }
+        if (!equal_real(e1[ind1[i]].e, e2[ind2[i]].e, ftol_i, abstol_i))
+        {
+            fprintf(fp, "%-15s  step %3d:  %12g,  step %3d: %12g\n",
+                    enm1[ind1[i]].name,
+                    step1, e1[ind1[i]].e,
+                    step2, e2[ind2[i]].e);
+        }
+    }
+
+    sfree(tensi);
+}
+
+#if 0
+static void cmp_disres(t_enxframe *fr1, t_enxframe *fr2, real ftol, real abstol)
+{
+    int  i;
+    char bav[64], bt[64], bs[22];
+
+    cmp_int(stdout, "ndisre", -1, fr1->ndisre, fr2->ndisre);
+    if ((fr1->ndisre == fr2->ndisre) && (fr1->ndisre > 0))
+    {
+        sprintf(bav, "step %s: disre rav", gmx_step_str(fr1->step, bs));
+        sprintf(bt, "step %s: disre  rt", gmx_step_str(fr1->step, bs));
+        for (i = 0; (i < fr1->ndisre); i++)
+        {
+            cmp_real(stdout, bav, i, fr1->disre_rm3tav[i], fr2->disre_rm3tav[i], ftol, abstol);
+            cmp_real(stdout, bt, i, fr1->disre_rt[i], fr2->disre_rt[i], ftol, abstol);
+        }
+    }
+}
+#endif
+
+static void cmp_eblocks(t_enxframe *fr1, t_enxframe *fr2, real ftol, real abstol)
+{
+    int  i, j, k;
+    char buf[64], bs[22];
+
+    cmp_int(stdout, "nblock", -1, fr1->nblock, fr2->nblock);
+    if ((fr1->nblock == fr2->nblock) && (fr1->nblock > 0))
+    {
+        for (j = 0; (j < fr1->nblock); j++)
+        {
+            t_enxblock *b1, *b2; /* convenience vars */
+
+            b1 = &(fr1->block[j]);
+            b2 = &(fr2->block[j]);
+
+            sprintf(buf, "step %s: block[%d]", gmx_step_str(fr1->step, bs), j);
+            cmp_int(stdout, buf, -1, b1->nsub, b2->nsub);
+            cmp_int(stdout, buf, -1, b1->id, b2->id);
+
+            if ( (b1->nsub == b2->nsub) && (b1->id == b2->id) )
+            {
+                for (i = 0; i < b1->nsub; i++)
+                {
+                    t_enxsubblock *s1, *s2;
+
+                    s1 = &(b1->sub[i]);
+                    s2 = &(b2->sub[i]);
+
+                    cmp_int(stdout, buf, -1, (int)s1->type, (int)s2->type);
+                    cmp_int64(stdout, buf, s1->nr, s2->nr);
+
+                    if ((s1->type == s2->type) && (s1->nr == s2->nr))
+                    {
+                        switch (s1->type)
+                        {
+                            case xdr_datatype_float:
+                                for (k = 0; k < s1->nr; k++)
+                                {
+                                    cmp_float(stdout, buf, i,
+                                              s1->fval[k], s2->fval[k],
+                                              ftol, abstol);
+                                }
+                                break;
+                            case xdr_datatype_double:
+                                for (k = 0; k < s1->nr; k++)
+                                {
+                                    cmp_double(stdout, buf, i,
+                                               s1->dval[k], s2->dval[k],
+                                               ftol, abstol);
+                                }
+                                break;
+                            case xdr_datatype_int:
+                                for (k = 0; k < s1->nr; k++)
+                                {
+                                    cmp_int(stdout, buf, i,
+                                            s1->ival[k], s2->ival[k]);
+                                }
+                                break;
+                            case xdr_datatype_int64:
+                                for (k = 0; k < s1->nr; k++)
+                                {
+                                    cmp_int64(stdout, buf,
+                                              s1->lval[k], s2->lval[k]);
+                                }
+                                break;
+                            case xdr_datatype_char:
+                                for (k = 0; k < s1->nr; k++)
+                                {
+                                    cmp_uc(stdout, buf, i,
+                                           s1->cval[k], s2->cval[k]);
+                                }
+                                break;
+                            case xdr_datatype_string:
+                                for (k = 0; k < s1->nr; k++)
+                                {
+                                    cmp_str(stdout, buf, i,
+                                            s1->sval[k], s2->sval[k]);
+                                }
+                                break;
+                            default:
+                                gmx_incons("Unknown data type!!");
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+void comp_enx(const char *fn1, const char *fn2, real ftol, real abstol, const char *lastener)
+{
+    int            nre, nre1, nre2;
+    ener_file_t    in1, in2;
+    int            i, j, maxener, *ind1, *ind2, *have;
+    gmx_enxnm_t   *enm1 = NULL, *enm2 = NULL;
+    t_enxframe    *fr1, *fr2;
+    gmx_bool       b1, b2;
+
+    fprintf(stdout, "comparing energy file %s and %s\n\n", fn1, fn2);
+
+    in1 = open_enx(fn1, "r");
+    in2 = open_enx(fn2, "r");
+    do_enxnms(in1, &nre1, &enm1);
+    do_enxnms(in2, &nre2, &enm2);
+    if (nre1 != nre2)
+    {
+        fprintf(stdout, "There are %d and %d terms in the energy files\n\n",
+                nre1, nre2);
+    }
+    else
+    {
+        fprintf(stdout, "There are %d terms in the energy files\n\n", nre1);
+    }
+
+    snew(ind1, nre1);
+    snew(ind2, nre2);
+    snew(have, nre2);
+    nre = 0;
+    for (i = 0; i < nre1; i++)
+    {
+        for (j = 0; j < nre2; j++)
+        {
+            if (enernm_equal(enm1[i].name, enm2[j].name))
+            {
+                ind1[nre] = i;
+                ind2[nre] = j;
+                have[j]   = 1;
+                nre++;
+                break;
+            }
+        }
+        if (nre == 0 || ind1[nre-1] != i)
+        {
+            cmp_str(stdout, "enm", i, enm1[i].name, "-");
+        }
+    }
+    for (i = 0; i < nre2; i++)
+    {
+        if (have[i] == 0)
+        {
+            cmp_str(stdout, "enm", i, "-", enm2[i].name);
+        }
+    }
+
+    maxener = nre;
+    for (i = 0; i < nre; i++)
+    {
+        if ((lastener != NULL) && (std::strstr(enm1[i].name, lastener) != NULL))
+        {
+            maxener = i+1;
+            break;
+        }
+    }
+
+    fprintf(stdout, "There are %d terms to compare in the energy files\n\n",
+            maxener);
+
+    for (i = 0; i < maxener; i++)
+    {
+        cmp_str(stdout, "unit", i, enm1[ind1[i]].unit, enm2[ind2[i]].unit);
+    }
+
+    snew(fr1, 1);
+    snew(fr2, 1);
+    do
+    {
+        b1 = do_enx(in1, fr1);
+        b2 = do_enx(in2, fr2);
+        if (b1 && !b2)
+        {
+            fprintf(stdout, "\nEnd of file on %s but not on %s\n", fn2, fn1);
+        }
+        else if (!b1 && b2)
+        {
+            fprintf(stdout, "\nEnd of file on %s but not on %s\n", fn1, fn2);
+        }
+        else if (!b1 && !b2)
+        {
+            fprintf(stdout, "\nFiles read successfully\n");
+        }
+        else
+        {
+            cmp_real(stdout, "t", -1, fr1->t, fr2->t, ftol, abstol);
+            cmp_int(stdout, "step", -1, fr1->step, fr2->step);
+            /* We don't want to print the nre mismatch for every frame */
+            /* cmp_int(stdout,"nre",-1,fr1->nre,fr2->nre); */
+            if ((fr1->nre >= nre) && (fr2->nre >= nre))
+            {
+                cmp_energies(stdout, fr1->step, fr1->step, fr1->ener, fr2->ener,
+                             enm1, ftol, abstol, nre, ind1, ind2, maxener);
+            }
+            /*cmp_disres(fr1,fr2,ftol,abstol);*/
+            cmp_eblocks(fr1, fr2, ftol, abstol);
+        }
+    }
+    while (b1 && b2);
+
+    close_enx(in1);
+    close_enx(in2);
+
+    free_enxframe(fr2);
+    sfree(fr2);
+    free_enxframe(fr1);
+    sfree(fr1);
+}
index c9c9807885635aca5d040014a502d9f69f4f68d6..f9ccc534111858a9a5a5ae7b96f950d75125a05a 100644 (file)
 #include "gromacs/mdtypes/state.h"
 #include "gromacs/trajectory/energy.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 struct gmx_groups_t;
 struct t_fileio;
 struct t_inputrec;
@@ -216,10 +212,8 @@ t_enxblock *find_block_id_enxframe(t_enxframe *ef, int id, t_enxblock *prev);
    subbblocks. */
 void add_subblocks_enxblock(t_enxblock *eb, int n);
 
-
-
-#ifdef __cplusplus
-}
-#endif
+void comp_enx(const char *fn1, const char *fn2, real ftol, real abstol,
+              const char *lastener);
+/* Compare two binary energy files */
 
 #endif
index f101cda68c645d2ad61c99f4f2c0641fe01cbec4..8ea7da89053e527b8c8b41874666f7a55a2cea1c 100644 (file)
@@ -164,9 +164,9 @@ static const char *const esp_prop[espNR] = {
 };
 
 void gmx_espresso_read_conf(const char *infile,
-                            t_topology *top, rvec x[], rvec *v, matrix box)
+                            t_symtab *symtab, char ***name, t_atoms *atoms,
+                            rvec x[], rvec *v, matrix box)
 {
-    t_atoms  *atoms = &top->atoms;
     FILE     *fp;
     char      word[STRLEN], buf[STRLEN];
     int       level, r, nprop, p, i, m, molnr;
@@ -174,11 +174,17 @@ void gmx_espresso_read_conf(const char *infile,
     double    d;
     gmx_bool  bFoundParticles, bFoundProp, bFoundVariable, bMol;
 
-    // TODO: The code does not understand titles it writes...
-    top->name = put_symtab(&top->symtab, "");
+    // No title reading implemented for espresso files
+    *name = put_symtab(symtab, "");
 
     clear_mat(box);
 
+    atoms->haveMass    = FALSE;
+    atoms->haveCharge  = FALSE;
+    atoms->haveType    = FALSE;
+    atoms->haveBState  = FALSE;
+    atoms->havePdbInfo = FALSE;
+
     fp = gmx_fio_fopen(infile, "r");
 
     bFoundParticles = FALSE;
@@ -201,7 +207,15 @@ void gmx_espresso_read_conf(const char *infile,
                     {
                         bFoundProp    = TRUE;
                         prop[nprop++] = p;
-                        /* printf("  prop[%d] = %s\n",nprop-1,esp_prop[prop[nprop-1]]); */
+                        if (p == espQ)
+                        {
+                            atoms->haveCharge = TRUE;
+                        }
+
+                        if (debug)
+                        {
+                            fprintf(debug, "  prop[%d] = %s\n", nprop-1, esp_prop[prop[nprop-1]]);
+                        }
                     }
                 }
                 if (!bFoundProp && word[0] != '}')
@@ -293,13 +307,13 @@ void gmx_espresso_read_conf(const char *infile,
                     }
                     /* Generate an atom name from the particle type */
                     sprintf(buf, "T%hu", atoms->atom[i].type);
-                    atoms->atomname[i] = put_symtab(&top->symtab, buf);
+                    atoms->atomname[i] = put_symtab(symtab, buf);
                     if (bMol)
                     {
                         if (i == 0 || atoms->atom[i].resind != atoms->atom[i-1].resind)
                         {
                             atoms->resinfo[atoms->atom[i].resind].name =
-                                put_symtab(&top->symtab, "MOL");
+                                put_symtab(symtab, "MOL");
                         }
                     }
                     else
@@ -316,7 +330,7 @@ void gmx_espresso_read_conf(const char *infile,
                             sprintf(buf, "T%c%c",
                                     'A'+atoms->atom[i].type/26, 'A'+atoms->atom[i].type%26);
                         }
-                        t_atoms_set_resinfo(atoms, i, &top->symtab, buf, i, ' ', 0, ' ');
+                        t_atoms_set_resinfo(atoms, i, symtab, buf, i, ' ', 0, ' ');
                     }
 
                     if (r == 3)
index b0d1fcba37c8d5dcb7f81a3ece7f11ea1302feb7..91cd9794740a4cc21232e96d0f5d57c762e855a6 100644 (file)
 #include "gromacs/math/vectypes.h"
 
 struct t_atoms;
-struct t_topology;
+struct t_symtab;
 
 void gmx_espresso_read_conf(const char *infile,
-                            t_topology *top, rvec x[], rvec *v, matrix box);
+                            t_symtab *symtab, char ***name, t_atoms *atoms,
+                            rvec x[], rvec *v, matrix box);
 
 int get_espresso_coordnum(const char *infile);
 
index eafc2ede65fec231f02dc5dc97610caac2d8c3fa..bfaf13309ee934881070c36620d22e6855cd4778 100644 (file)
@@ -66,6 +66,14 @@ static int read_g96_pos(char line[], t_symtab *symtab,
     nwanted = fr->natoms;
 
     atoms = fr->atoms;
+    if (atoms != NULL)
+    {
+        atoms->haveMass    = FALSE;
+        atoms->haveCharge  = FALSE;
+        atoms->haveType    = FALSE;
+        atoms->haveBState  = FALSE;
+        atoms->havePdbInfo = FALSE;
+    }
 
     natoms = 0;
 
index 0d3b70bb2587cbcb57698eff9488e32b3eb74f96..99f78af2a09e94146d710a3ca446e57c665fbe38 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -45,6 +45,7 @@
 #include "gromacs/fileio/xdrf.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/scoped_cptr.h"
 #include "gromacs/utility/smalloc.h"
 
 #include "gmxfio-impl.h"
@@ -672,3 +673,50 @@ gmx_bool gmx_fio_ndoe_string(t_fileio *fio, char *item[], int n,
     gmx_fio_unlock(fio);
     return ret;
 }
+
+namespace gmx
+{
+
+bool FileIOXdrSerializer::reading() const
+{
+    return fio_->bRead;
+}
+
+void FileIOXdrSerializer::doUChar(unsigned char *value)
+{
+    gmx_fio_do_uchar(fio_, *value);
+}
+
+void FileIOXdrSerializer::doInt(int *value)
+{
+    gmx_fio_do_int(fio_, *value);
+}
+
+void FileIOXdrSerializer::doFloat(float *value)
+{
+    gmx_fio_do_float(fio_, *value);
+}
+
+void FileIOXdrSerializer::doDouble(double *value)
+{
+    gmx_fio_do_double(fio_, *value);
+}
+
+void FileIOXdrSerializer::doString(std::string *value)
+{
+    // TODO: Use an arbitrary length buffer (but that is not supported in
+    // gmx_fio, either).
+    char buf[STRLEN];
+    if (!fio_->bRead)
+    {
+        std::strncpy(buf, value->c_str(), STRLEN);
+        buf[STRLEN-1] = 0;
+    }
+    gmx_fio_do_string(fio_, buf);
+    if (fio_->bRead)
+    {
+        *value = buf;
+    }
+}
+
+} // namespace gmx
index 982724d64fe4deeffafd0cc561531b5d832d81c2..16169a8b71377a5809725c5ba7fc5cc164248f13 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 #ifndef GMX_FILEIO_GMXFIO_XDR_H
 #define GMX_FILEIO_GMXFIO_XDR_H
 
+#include <string>
+
 #include "gromacs/fileio/xdrf.h"
 #include "gromacs/math/vectypes.h"
 #include "gromacs/utility/basedefinitions.h"
+#include "gromacs/utility/iserializer.h"
 #include "gromacs/utility/real.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 struct t_fileio;
 
 void gmx_fio_setprecision(struct t_fileio *fio, gmx_bool bDouble);
@@ -136,8 +135,26 @@ gmx_bool gmx_fio_ndoe_string(struct t_fileio *fio, char *item[], int n,
 #define gmx_fio_ndo_ivec(fio, item, n)              gmx_fio_ndoe_ivec(fio, item, n, (#item), __FILE__, __LINE__)
 #define gmx_fio_ndo_string(fio, item, n)            gmx_fio_ndoe_string(fio, item, n, (#item), __FILE__, __LINE__)
 
-#ifdef __cplusplus
-}
-#endif
+namespace gmx
+{
+
+class FileIOXdrSerializer : public ISerializer
+{
+    public:
+        explicit FileIOXdrSerializer(t_fileio *fio) : fio_(fio) {}
+
+        virtual bool reading() const;
+
+        virtual void doUChar(unsigned char *value);
+        virtual void doInt(int *value);
+        virtual void doFloat(float *value);
+        virtual void doDouble(double *value);
+        virtual void doString(std::string *value);
+
+    private:
+        t_fileio *fio_;
+};
+
+} // namespace gmx
 
 #endif
index 9b4e9f30585a15032d06cd8f02e6aaf2f6f59d9d..0aa130216cb5d1c1884c50ebf7b4d84795ca2459 100644 (file)
@@ -116,6 +116,12 @@ static gmx_bool get_w_conf(FILE *in, const char *infile, char *title,
                 " (%d)\n", natoms, atoms->nr);
     }
 
+    atoms->haveMass    = FALSE;
+    atoms->haveCharge  = FALSE;
+    atoms->haveType    = FALSE;
+    atoms->haveBState  = FALSE;
+    atoms->havePdbInfo = FALSE;
+
     bFirst = TRUE;
 
     bVel = FALSE;
@@ -302,13 +308,14 @@ static gmx_bool get_w_conf(FILE *in, const char *infile, char *title,
 }
 
 void gmx_gro_read_conf(const char *infile,
-                       t_topology *top, rvec x[], rvec *v, matrix box)
+                       t_symtab *symtab, char ***name, t_atoms *atoms,
+                       rvec x[], rvec *v, matrix box)
 {
     FILE *in = gmx_fio_fopen(infile, "r");
     int   ndec;
     char  title[STRLEN];
-    get_w_conf(in, infile, title, &top->symtab, &top->atoms, &ndec, x, v, box);
-    top->name = put_symtab(&top->symtab, title);
+    get_w_conf(in, infile, title, symtab, atoms, &ndec, x, v, box);
+    *name = put_symtab(symtab, title);
     gmx_fio_fclose(in);
 }
 
@@ -500,7 +507,7 @@ void write_hconf_mtop(FILE *out, const char *title, gmx_mtop_t *mtop,
 {
     int                     i, resnr;
     gmx_mtop_atomloop_all_t aloop;
-    t_atom                 *atom;
+    const t_atom           *atom;
     char                   *atomname, *resname;
 
     fprintf(out, "%s\n", (title && title[0]) ? title : gmx::bromacs().c_str());
index 3391e7df3dd44e11a1982d22a255c630e938c63f..53448ca1fff4a3c54663d9881c37cd799991255c 100644 (file)
@@ -48,12 +48,13 @@ extern "C" {
 
 struct gmx_mtop_t;
 struct t_atoms;
-struct t_topology;
+struct t_symtab;
 struct t_trxframe;
 
 void get_coordnum(const char *infile, int *natoms);
 void gmx_gro_read_conf(const char *infile,
-                       struct t_topology *top, rvec x[], rvec *v, matrix box);
+                       t_symtab *symtab, char ***name, t_atoms *atoms,
+                       rvec x[], rvec *v, matrix box);
 
 gmx_bool gro_next_x_or_v(FILE *status, struct t_trxframe *fr);
 int gro_first_x_or_v(FILE *status, struct t_trxframe *fr);
index a00699208499f533fd58515c998aab96a414fadf..fcc648f576e473fb624dd50881ce0091155b2cca 100644 (file)
 struct gmx_output_env_t
 {
     explicit gmx_output_env_t(const gmx::IProgramContext &context)
-        : programContext(context)
-    {
-        time_unit   = time_ps;
-        view        = FALSE;
-        xvg_format  = exvgNONE;
-        verbosity   = 0;
-    }
+        : programContext(context),
+          time_unit(time_ps),
+          view(FALSE),
+          xvg_format(exvgNONE),
+          verbosity(0) {}
 
     const gmx::IProgramContext  &programContext;
 
index ddedd79e71c36e4097c92ab74d3c6e7095f1eba9..7824afd521cc57389ecb8c2a5d23b80b389ed313 100644 (file)
@@ -286,7 +286,7 @@ void write_pdbfile_indexed(FILE *out, const char *title,
     {
         gmx_write_pdb_box(out, ePBC, box);
     }
-    if (atoms->pdbinfo)
+    if (atoms->havePdbInfo)
     {
         /* Check whether any occupancies are set, in that case leave it as is,
          * otherwise set them all to one
@@ -870,6 +870,12 @@ int read_pdbfile(FILE *in, char *title, int *model_nr,
         clear_mat(box);
     }
 
+    atoms->haveMass    = FALSE;
+    atoms->haveCharge  = FALSE;
+    atoms->haveType    = FALSE;
+    atoms->haveBState  = FALSE;
+    atoms->havePdbInfo = (atoms->pdbinfo != NULL);
+
     bCOMPND  = FALSE;
     title[0] = '\0';
     natom    = 0;
@@ -886,7 +892,7 @@ int read_pdbfile(FILE *in, char *title, int *model_nr,
                 break;
 
             case epdbANISOU:
-                if (atoms->pdbinfo)
+                if (atoms->havePdbInfo)
                 {
                     read_anisou(line, natom, atoms);
                 }
@@ -1018,12 +1024,13 @@ void get_pdb_coordnum(FILE *in, int *natoms)
 }
 
 void gmx_pdb_read_conf(const char *infile,
-                       t_topology *top, rvec x[], int *ePBC, matrix box)
+                       t_symtab *symtab, char ***name, t_atoms *atoms,
+                       rvec x[], int *ePBC, matrix box)
 {
     FILE *in = gmx_fio_fopen(infile, "r");
     char  title[STRLEN];
-    read_pdbfile(in, title, NULL, &top->atoms, &top->symtab, x, ePBC, box, TRUE, NULL);
-    top->name = put_symtab(&top->symtab, title);
+    read_pdbfile(in, title, NULL, atoms, symtab, x, ePBC, box, TRUE, NULL);
+    *name = put_symtab(symtab, title);
     gmx_fio_fclose(in);
 }
 
index 3c268708882f2c3311357c36f6a5356ab32ba3be..c5a0ee3e22e632e99b24ff665a2bc2f2320faded 100644 (file)
@@ -126,7 +126,8 @@ int read_pdbfile(FILE *in, char *title, int *model_nr,
  */
 
 void gmx_pdb_read_conf(const char *infile,
-                       struct t_topology *top, rvec x[], int *ePBC, matrix box);
+                       t_symtab *symtab, char ***name, t_atoms *atoms,
+                       rvec x[], int *ePBC, matrix box);
 /* Read a pdb file and extract ATOM and HETATM fields.
  * Read a box from the CRYST1 line, return 0 box when no CRYST1 is found.
  * ePBC may be NULL.
index 0f182a718c5389f1d44efd70aa0d843b3e8780e3..413f54dd569c6ef204cdd549e835df2597e181b5 100644 (file)
@@ -52,6 +52,7 @@
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/futil.h"
+#include "gromacs/utility/keyvaluetreebuilder.h"
 #include "gromacs/utility/programcontext.h"
 #include "gromacs/utility/qsort_threadsafe.h"
 #include "gromacs/utility/smalloc.h"
@@ -226,7 +227,17 @@ t_inpfile *read_inpfile(const char *fn, int *ninp,
     return inp;
 }
 
-
+gmx::KeyValueTreeObject flatKeyValueTreeFromInpFile(int ninp, t_inpfile inp[])
+{
+    gmx::KeyValueTreeBuilder  builder;
+    auto                      root = builder.rootObject();
+    for (int i = 0; i < ninp; ++i)
+    {
+        const char *value = inp[i].value;
+        root.addValue<std::string>(inp[i].name, value != nullptr ? value : "");
+    }
+    return builder.build();
+}
 
 
 static int inp_comp(const void *a, const void *b)
@@ -347,6 +358,16 @@ int search_einp(int ninp, const t_inpfile *inp, const char *name)
     return -1;
 }
 
+void mark_einp_set(int ninp, t_inpfile *inp, const char *name)
+{
+    int i = search_einp(ninp, inp, name);
+    if (i != -1)
+    {
+        inp[i].count = inp[0].inp_count++;
+        inp[i].bSet  = TRUE;
+    }
+}
+
 static int get_einp(int *ninp, t_inpfile **inp, const char *name)
 {
     int    i;
index ead2d0d3d69cecba83fbcaa3479ba1f2285b2b77..0c3bb3542d60172fb46a391670efa26f17ce1f94 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 #include "gromacs/fileio/warninp.h"
 #include "gromacs/utility/basedefinitions.h"
 
-typedef struct {
+namespace gmx
+{
+class KeyValueTreeObject;
+}
+
+typedef struct t_inpfile {
     int      count;     /* sort order for output  */
     gmx_bool bObsolete; /* whether it is an obsolete param value */
     gmx_bool bSet;      /* whether it it has been read out */
@@ -62,6 +67,8 @@ t_inpfile *read_inpfile(const char *fn, int *ninp,
    ninp = the number of read parameters
    cppopts = the cpp-style options for #include paths and #defines */
 
+gmx::KeyValueTreeObject flatKeyValueTreeFromInpFile(int ninp, t_inpfile inp[]);
+
 void write_inpfile(const char *fn, int ninp, t_inpfile inp[],
                    gmx_bool bHaltOnUnknown,
                    warninp_t wi);
@@ -72,6 +79,7 @@ void replace_inp_entry(int ninp, t_inpfile *inp,
 int search_einp(int ninp, const t_inpfile *inp, const char *name);
 /* Return the index of an .mdp field with the given name within the
  * inp array, if it exists. Return -1 if it does not exist. */
+void mark_einp_set(int ninp, t_inpfile *inp, const char *name);
 
 int get_eint(int *ninp, t_inpfile **inp, const char *name, int def,
              warninp_t wi);
index 2863a9795d7cd1b5e4d893a94dbbb0aa4dbeda27..aff4ee969be653ba30b7488b583ea21fd72079de 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -181,7 +181,7 @@ class StructureIORoundtripTest : public gmx::test::StringTestBase,
             refX_.reserve(atomCount);
             for (int i = 0; i < atomCount; ++i)
             {
-                refX_.push_back(gmx::RVec(i%4, i/4, (i/2)%3));
+                refX_.emplace_back(i%4, i/4, (i/2)%3);
             }
         }
 
index 6c5cbef3498731ad88b6e7074bce1c9f10b96629..2b19f25c33bb9dd4457cbc223caa359e09e11a4e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2013,2014, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -47,7 +47,6 @@
 
 #include <gtest/gtest.h>
 
-#include "gromacs/fileio/tngio_for_tools.h"
 #include "gromacs/utility/path.h"
 
 #include "testutils/testfilemanager.h"
index 13d9cbd70ed14ce4a7b9be4a3ed84de68641c3bc..8c4052a210681814235e49cef1ac1cd64ae21581 100644 (file)
 
 #include "config.h"
 
+#include <cmath>
+
+#include <memory>
+
 #if GMX_USE_TNG
 #include "tng/tng_io.h"
 #endif
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/topology/ifunc.h"
 #include "gromacs/topology/topology.h"
+#include "gromacs/trajectory/trajectoryframe.h"
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/baseversion.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/futil.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/programcontext.h"
+#include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/sysinfo.h"
 
 static const char *modeToVerb(char mode)
@@ -868,3 +874,835 @@ float gmx_tng_get_time_of_final_frame(tng_trajectory_t tng)
     return -1.0;
 #endif
 }
+
+void gmx_prepare_tng_writing(const char              *filename,
+                             char                     mode,
+                             tng_trajectory_t        *input,
+                             tng_trajectory_t        *output,
+                             int                      nAtoms,
+                             const gmx_mtop_t        *mtop,
+                             const int               *index,
+                             const char              *indexGroupName)
+{
+#if GMX_USE_TNG
+    /* FIXME after 5.0: Currently only standard block types are read */
+    const int           defaultNumIds              = 5;
+    static gmx_int64_t  fallbackIds[defaultNumIds] =
+    {
+        TNG_TRAJ_BOX_SHAPE, TNG_TRAJ_POSITIONS,
+        TNG_TRAJ_VELOCITIES, TNG_TRAJ_FORCES,
+        TNG_GMX_LAMBDA
+    };
+    static char         fallbackNames[defaultNumIds][32] =
+    {
+        "BOX SHAPE", "POSITIONS", "VELOCITIES",
+        "FORCES", "LAMBDAS"
+    };
+
+    typedef tng_function_status (*set_writing_interval_func_pointer)(tng_trajectory_t,
+                                                                     const gmx_int64_t,
+                                                                     const gmx_int64_t,
+                                                                     const gmx_int64_t,
+                                                                     const char*,
+                                                                     const char,
+                                                                     const char);
+#if GMX_DOUBLE
+    set_writing_interval_func_pointer set_writing_interval = tng_util_generic_write_interval_double_set;
+#else
+    set_writing_interval_func_pointer set_writing_interval = tng_util_generic_write_interval_set;
+#endif
+
+    gmx_tng_open(filename, mode, output);
+
+    /* Do we have an input file in TNG format? If so, then there's
+       more data we can copy over, rather than having to improvise. */
+    if (*input)
+    {
+        /* Set parameters (compression, time per frame, molecule
+         * information, number of frames per frame set and writing
+         * intervals of positions, box shape and lambdas) of the
+         * output tng container based on their respective values int
+         * the input tng container */
+        double      time, compression_precision;
+        gmx_int64_t n_frames_per_frame_set, interval = -1;
+
+        tng_compression_precision_get(*input, &compression_precision);
+        tng_compression_precision_set(*output, compression_precision);
+        // TODO make this configurable in a future version
+        char compression_type = TNG_TNG_COMPRESSION;
+
+        tng_molecule_system_copy(*input, *output);
+
+        tng_time_per_frame_get(*input, &time);
+        tng_time_per_frame_set(*output, time);
+
+        tng_num_frames_per_frame_set_get(*input, &n_frames_per_frame_set);
+        tng_num_frames_per_frame_set_set(*output, n_frames_per_frame_set);
+
+        for (int i = 0; i < defaultNumIds; i++)
+        {
+            if (tng_data_get_stride_length(*input, fallbackIds[i], -1, &interval)
+                == TNG_SUCCESS)
+            {
+                switch (fallbackIds[i])
+                {
+                    case TNG_TRAJ_POSITIONS:
+                    case TNG_TRAJ_VELOCITIES:
+                        set_writing_interval(*output, interval, 3, fallbackIds[i],
+                                             fallbackNames[i], TNG_PARTICLE_BLOCK_DATA,
+                                             compression_type);
+                        break;
+                    case TNG_TRAJ_FORCES:
+                        set_writing_interval(*output, interval, 3, fallbackIds[i],
+                                             fallbackNames[i], TNG_PARTICLE_BLOCK_DATA,
+                                             TNG_GZIP_COMPRESSION);
+                        break;
+                    case TNG_TRAJ_BOX_SHAPE:
+                        set_writing_interval(*output, interval, 9, fallbackIds[i],
+                                             fallbackNames[i], TNG_NON_PARTICLE_BLOCK_DATA,
+                                             TNG_GZIP_COMPRESSION);
+                        break;
+                    case TNG_GMX_LAMBDA:
+                        set_writing_interval(*output, interval, 1, fallbackIds[i],
+                                             fallbackNames[i], TNG_NON_PARTICLE_BLOCK_DATA,
+                                             TNG_GZIP_COMPRESSION);
+                    default:
+                        continue;
+                }
+            }
+        }
+
+    }
+    else
+    {
+        /* TODO after trjconv is modularized: fix this so the user can
+           change precision when they are doing an operation where
+           this makes sense, and not otherwise.
+
+           char compression = bUseLossyCompression ? TNG_TNG_COMPRESSION : TNG_GZIP_COMPRESSION;
+           gmx_tng_set_compression_precision(*output, ndec2prec(nDecimalsOfPrecision));
+         */
+        gmx_tng_add_mtop(*output, mtop);
+        tng_num_frames_per_frame_set_set(*output, 1);
+    }
+
+    if (index && nAtoms > 0)
+    {
+        gmx_tng_setup_atom_subgroup(*output, nAtoms, index, indexGroupName);
+    }
+
+    /* If for some reason there are more requested atoms than there are atoms in the
+     * molecular system create a number of implicit atoms (without atom data) to
+     * compensate for that. */
+    if (nAtoms >= 0)
+    {
+        tng_implicit_num_particles_set(*output, nAtoms);
+    }
+#else
+    GMX_UNUSED_VALUE(filename);
+    GMX_UNUSED_VALUE(mode);
+    GMX_UNUSED_VALUE(input);
+    GMX_UNUSED_VALUE(output);
+    GMX_UNUSED_VALUE(nAtoms);
+    GMX_UNUSED_VALUE(mtop);
+    GMX_UNUSED_VALUE(index);
+    GMX_UNUSED_VALUE(indexGroupName);
+#endif
+}
+
+void gmx_write_tng_from_trxframe(tng_trajectory_t        output,
+                                 const t_trxframe       *frame,
+                                 int                     natoms)
+{
+#if GMX_USE_TNG
+    if (frame->step > 0)
+    {
+        double timePerFrame = frame->time * PICO / frame->step;
+        tng_time_per_frame_set(output, timePerFrame);
+    }
+    if (natoms < 0)
+    {
+        natoms = frame->natoms;
+    }
+    gmx_fwrite_tng(output,
+                   TRUE,
+                   frame->step,
+                   frame->time,
+                   0,
+                   frame->box,
+                   natoms,
+                   frame->x,
+                   frame->v,
+                   frame->f);
+#else
+    GMX_UNUSED_VALUE(output);
+    GMX_UNUSED_VALUE(frame);
+    GMX_UNUSED_VALUE(natoms);
+#endif
+}
+
+namespace
+{
+
+#if GMX_USE_TNG
+void
+convert_array_to_real_array(void       *from,
+                            real       *to,
+                            const float fact,
+                            const int   nAtoms,
+                            const int   nValues,
+                            const char  datatype)
+{
+    int        i, j;
+
+    const bool useDouble = GMX_DOUBLE;
+    switch (datatype)
+    {
+        case TNG_FLOAT_DATA:
+            if (!useDouble)
+            {
+                if (fact == 1)
+                {
+                    memcpy(to, from, nValues * sizeof(real) * nAtoms);
+                }
+                else
+                {
+                    for (i = 0; i < nAtoms; i++)
+                    {
+                        for (j = 0; j < nValues; j++)
+                        {
+                            to[i*nValues+j] = reinterpret_cast<float *>(from)[i*nValues+j] * fact;
+                        }
+                    }
+                }
+            }
+            else
+            {
+                for (i = 0; i < nAtoms; i++)
+                {
+                    for (j = 0; j < nValues; j++)
+                    {
+                        to[i*nValues+j] = reinterpret_cast<float *>(from)[i*nValues+j] * fact;
+                    }
+                }
+            }
+            break;
+        case TNG_INT_DATA:
+            for (i = 0; i < nAtoms; i++)
+            {
+                for (j = 0; j < nValues; j++)
+                {
+                    to[i*nValues+j] = reinterpret_cast<gmx_int64_t *>(from)[i*nValues+j] * fact;
+                }
+            }
+            break;
+        case TNG_DOUBLE_DATA:
+            if (sizeof(real) == sizeof(double))
+            {
+                if (fact == 1)
+                {
+                    memcpy(to, from, nValues * sizeof(real) * nAtoms);
+                }
+                else
+                {
+                    for (i = 0; i < nAtoms; i++)
+                    {
+                        for (j = 0; j < nValues; j++)
+                        {
+                            to[i*nValues+j] = reinterpret_cast<double *>(from)[i*nValues+j] * fact;
+                        }
+                    }
+                }
+            }
+            else
+            {
+                for (i = 0; i < nAtoms; i++)
+                {
+                    for (j = 0; j < nValues; j++)
+                    {
+                        to[i*nValues+j] = reinterpret_cast<double *>(from)[i*nValues+j] * fact;
+                    }
+                }
+            }
+            break;
+        default:
+            gmx_incons("Illegal datatype when converting values to a real array!");
+            return;
+    }
+    return;
+}
+
+real getDistanceScaleFactor(tng_trajectory_t in)
+{
+    gmx_int64_t exp = -1;
+    real        distanceScaleFactor;
+
+    // TODO Hopefully, TNG 2.0 will do this kind of thing for us
+    tng_distance_unit_exponential_get(in, &exp);
+
+    // GROMACS expects distances in nm
+    switch (exp)
+    {
+        case 9:
+            distanceScaleFactor = NANO/NANO;
+            break;
+        case 10:
+            distanceScaleFactor = NANO/ANGSTROM;
+            break;
+        default:
+            distanceScaleFactor = pow(10.0, exp + 9.0);
+    }
+
+    return distanceScaleFactor;
+}
+#endif
+
+} // namespace
+
+void gmx_tng_setup_atom_subgroup(tng_trajectory_t tng,
+                                 const int        nind,
+                                 const int       *ind,
+                                 const char      *name)
+{
+#if GMX_USE_TNG
+    gmx_int64_t              nAtoms, cnt, nMols;
+    tng_molecule_t           mol, iterMol;
+    tng_chain_t              chain;
+    tng_residue_t            res;
+    tng_atom_t               atom;
+    tng_function_status      stat;
+
+    tng_num_particles_get(tng, &nAtoms);
+
+    if (nAtoms == nind)
+    {
+        return;
+    }
+
+    stat = tng_molecule_find(tng, name, -1, &mol);
+    if (stat == TNG_SUCCESS)
+    {
+        tng_molecule_num_atoms_get(tng, mol, &nAtoms);
+        tng_molecule_cnt_get(tng, mol, &cnt);
+        if (nAtoms == nind)
+        {
+            stat = TNG_SUCCESS;
+        }
+        else
+        {
+            stat = TNG_FAILURE;
+        }
+    }
+    if (stat == TNG_FAILURE)
+    {
+        /* The indexed atoms are added to one separate molecule. */
+        tng_molecule_alloc(tng, &mol);
+        tng_molecule_name_set(tng, mol, name);
+        tng_molecule_chain_add(tng, mol, "", &chain);
+
+        for (int i = 0; i < nind; i++)
+        {
+            char        temp_name[256], temp_type[256];
+
+            /* Try to retrieve the residue name of the atom */
+            stat = tng_residue_name_of_particle_nr_get(tng, ind[i], temp_name, 256);
+            if (stat != TNG_SUCCESS)
+            {
+                temp_name[0] = '\0';
+            }
+            /* Check if the molecule of the selection already contains this residue */
+            if (tng_chain_residue_find(tng, chain, temp_name, -1, &res)
+                != TNG_SUCCESS)
+            {
+                tng_chain_residue_add(tng, chain, temp_name, &res);
+            }
+            /* Try to find the original name and type of the atom */
+            stat = tng_atom_name_of_particle_nr_get(tng, ind[i], temp_name, 256);
+            if (stat != TNG_SUCCESS)
+            {
+                temp_name[0] = '\0';
+            }
+            stat = tng_atom_type_of_particle_nr_get(tng, ind[i], temp_type, 256);
+            if (stat != TNG_SUCCESS)
+            {
+                temp_type[0] = '\0';
+            }
+            tng_residue_atom_w_id_add(tng, res, temp_name, temp_type, ind[i], &atom);
+        }
+        tng_molecule_existing_add(tng, &mol);
+    }
+    /* Set the count of the molecule containing the selected atoms to 1 and all
+     * other molecules to 0 */
+    tng_molecule_cnt_set(tng, mol, 1);
+    tng_num_molecule_types_get(tng, &nMols);
+    for (gmx_int64_t k = 0; k < nMols; k++)
+    {
+        tng_molecule_of_index_get(tng, k, &iterMol);
+        if (iterMol == mol)
+        {
+            continue;
+        }
+        tng_molecule_cnt_set(tng, iterMol, 0);
+    }
+#else
+    GMX_UNUSED_VALUE(tng);
+    GMX_UNUSED_VALUE(nind);
+    GMX_UNUSED_VALUE(ind);
+    GMX_UNUSED_VALUE(name);
+#endif
+}
+
+/* TODO: If/when TNG acquires the ability to copy data blocks without
+ * uncompressing them, then this implemenation should be reconsidered.
+ * Ideally, gmx trjconv -f a.tng -o b.tng -b 10 -e 20 would be fast
+ * and lose no information. */
+gmx_bool gmx_read_next_tng_frame(tng_trajectory_t            input,
+                                 t_trxframe                 *fr,
+                                 gmx_int64_t                *requestedIds,
+                                 int                         numRequestedIds)
+{
+#if GMX_USE_TNG
+    gmx_bool                bOK = TRUE;
+    tng_function_status     stat;
+    gmx_int64_t             numberOfAtoms = -1, frameNumber = -1;
+    gmx_int64_t             nBlocks, blockId, *blockIds = NULL, codecId;
+    char                    datatype      = -1;
+    void                   *values        = NULL;
+    double                  frameTime     = -1.0;
+    int                     size, blockDependency;
+    double                  prec;
+    const int               defaultNumIds = 5;
+    static gmx_int64_t      fallbackRequestedIds[defaultNumIds] =
+    {
+        TNG_TRAJ_BOX_SHAPE, TNG_TRAJ_POSITIONS,
+        TNG_TRAJ_VELOCITIES, TNG_TRAJ_FORCES,
+        TNG_GMX_LAMBDA
+    };
+
+
+    fr->bStep     = FALSE;
+    fr->bTime     = FALSE;
+    fr->bLambda   = FALSE;
+    fr->bAtoms    = FALSE;
+    fr->bPrec     = FALSE;
+    fr->bX        = FALSE;
+    fr->bV        = FALSE;
+    fr->bF        = FALSE;
+    fr->bBox      = FALSE;
+
+    /* If no specific IDs were requested read all block types that can
+     * currently be interpreted */
+    if (!requestedIds || numRequestedIds == 0)
+    {
+        numRequestedIds = defaultNumIds;
+        requestedIds    = fallbackRequestedIds;
+    }
+
+    stat = tng_num_particles_get(input, &numberOfAtoms);
+    if (stat != TNG_SUCCESS)
+    {
+        gmx_file("Cannot determine number of atoms from TNG file.");
+    }
+    fr->natoms = numberOfAtoms;
+
+    if (!gmx_get_tng_data_block_types_of_next_frame(input,
+                                                    fr->step,
+                                                    numRequestedIds,
+                                                    requestedIds,
+                                                    &frameNumber,
+                                                    &nBlocks,
+                                                    &blockIds))
+    {
+        return FALSE;
+    }
+
+    if (nBlocks == 0)
+    {
+        return FALSE;
+    }
+
+    for (gmx_int64_t i = 0; i < nBlocks; i++)
+    {
+        blockId = blockIds[i];
+        tng_data_block_dependency_get(input, blockId, &blockDependency);
+        if (blockDependency & TNG_PARTICLE_DEPENDENT)
+        {
+            stat = tng_util_particle_data_next_frame_read(input,
+                                                          blockId,
+                                                          &values,
+                                                          &datatype,
+                                                          &frameNumber,
+                                                          &frameTime);
+        }
+        else
+        {
+            stat = tng_util_non_particle_data_next_frame_read(input,
+                                                              blockId,
+                                                              &values,
+                                                              &datatype,
+                                                              &frameNumber,
+                                                              &frameTime);
+        }
+        if (stat == TNG_CRITICAL)
+        {
+            gmx_file("Cannot read positions from TNG file.");
+            return FALSE;
+        }
+        else if (stat == TNG_FAILURE)
+        {
+            continue;
+        }
+        switch (blockId)
+        {
+            case TNG_TRAJ_BOX_SHAPE:
+                switch (datatype)
+                {
+                    case TNG_INT_DATA:
+                        size = sizeof(gmx_int64_t);
+                        break;
+                    case TNG_FLOAT_DATA:
+                        size = sizeof(float);
+                        break;
+                    case TNG_DOUBLE_DATA:
+                        size = sizeof(double);
+                        break;
+                    default:
+                        gmx_incons("Illegal datatype of box shape values!");
+                }
+                for (int i = 0; i < DIM; i++)
+                {
+                    convert_array_to_real_array(reinterpret_cast<char *>(values) + size * i * DIM,
+                                                reinterpret_cast<real *>(fr->box[i]),
+                                                getDistanceScaleFactor(input),
+                                                1,
+                                                DIM,
+                                                datatype);
+                }
+                fr->bBox = TRUE;
+                break;
+            case TNG_TRAJ_POSITIONS:
+                srenew(fr->x, fr->natoms);
+                convert_array_to_real_array(values,
+                                            reinterpret_cast<real *>(fr->x),
+                                            getDistanceScaleFactor(input),
+                                            fr->natoms,
+                                            DIM,
+                                            datatype);
+                fr->bX = TRUE;
+                tng_util_frame_current_compression_get(input, blockId, &codecId, &prec);
+                /* This must be updated if/when more lossy compression methods are added */
+                if (codecId == TNG_TNG_COMPRESSION)
+                {
+                    fr->prec  = prec;
+                    fr->bPrec = TRUE;
+                }
+                break;
+            case TNG_TRAJ_VELOCITIES:
+                srenew(fr->v, fr->natoms);
+                convert_array_to_real_array(values,
+                                            (real *) fr->v,
+                                            getDistanceScaleFactor(input),
+                                            fr->natoms,
+                                            DIM,
+                                            datatype);
+                fr->bV = TRUE;
+                tng_util_frame_current_compression_get(input, blockId, &codecId, &prec);
+                /* This must be updated if/when more lossy compression methods are added */
+                if (codecId == TNG_TNG_COMPRESSION)
+                {
+                    fr->prec  = prec;
+                    fr->bPrec = TRUE;
+                }
+                break;
+            case TNG_TRAJ_FORCES:
+                srenew(fr->f, fr->natoms);
+                convert_array_to_real_array(values,
+                                            reinterpret_cast<real *>(fr->f),
+                                            getDistanceScaleFactor(input),
+                                            fr->natoms,
+                                            DIM,
+                                            datatype);
+                fr->bF = TRUE;
+                break;
+            case TNG_GMX_LAMBDA:
+                switch (datatype)
+                {
+                    case TNG_FLOAT_DATA:
+                        fr->lambda = *(reinterpret_cast<float *>(values));
+                        break;
+                    case TNG_DOUBLE_DATA:
+                        fr->lambda = *(reinterpret_cast<double *>(values));
+                        break;
+                    default:
+                        gmx_incons("Illegal datatype lambda value!");
+                }
+                fr->bLambda = TRUE;
+                break;
+            default:
+                gmx_warning("Illegal block type! Currently GROMACS tools can only handle certain data types. Skipping block.");
+        }
+        /* values does not have to be freed before reading next frame. It will
+         * be reallocated if it is not NULL. */
+    }
+
+    fr->step  = frameNumber;
+    fr->bStep = TRUE;
+    // Convert the time to ps
+    fr->time  = frameTime / PICO;
+    fr->bTime = TRUE;
+
+    /* values must be freed before leaving this function */
+    sfree(values);
+
+    return bOK;
+#else
+    GMX_UNUSED_VALUE(input);
+    GMX_UNUSED_VALUE(fr);
+    GMX_UNUSED_VALUE(requestedIds);
+    GMX_UNUSED_VALUE(numRequestedIds);
+    return FALSE;
+#endif
+}
+
+void gmx_print_tng_molecule_system(tng_trajectory_t input,
+                                   FILE            *stream)
+{
+#if GMX_USE_TNG
+    gmx_int64_t        nMolecules, nChains, nResidues, nAtoms, *molCntList;
+    tng_molecule_t     molecule;
+    tng_chain_t        chain;
+    tng_residue_t      residue;
+    tng_atom_t         atom;
+    char               str[256], varNAtoms;
+
+    tng_num_molecule_types_get(input, &nMolecules);
+    tng_molecule_cnt_list_get(input, &molCntList);
+    /* Can the number of particles change in the trajectory or is it constant? */
+    tng_num_particles_variable_get(input, &varNAtoms);
+
+    for (gmx_int64_t i = 0; i < nMolecules; i++)
+    {
+        tng_molecule_of_index_get(input, i, &molecule);
+        tng_molecule_name_get(input, molecule, str, 256);
+        if (varNAtoms == TNG_CONSTANT_N_ATOMS)
+        {
+            if ((int)molCntList[i] == 0)
+            {
+                continue;
+            }
+            fprintf(stream, "Molecule: %s, count: %d\n", str, (int)molCntList[i]);
+        }
+        else
+        {
+            fprintf(stream, "Molecule: %s\n", str);
+        }
+        tng_molecule_num_chains_get(input, molecule, &nChains);
+        if (nChains > 0)
+        {
+            for (gmx_int64_t j = 0; j < nChains; j++)
+            {
+                tng_molecule_chain_of_index_get(input, molecule, j, &chain);
+                tng_chain_name_get(input, chain, str, 256);
+                fprintf(stream, "\tChain: %s\n", str);
+                tng_chain_num_residues_get(input, chain, &nResidues);
+                for (gmx_int64_t k = 0; k < nResidues; k++)
+                {
+                    tng_chain_residue_of_index_get(input, chain, k, &residue);
+                    tng_residue_name_get(input, residue, str, 256);
+                    fprintf(stream, "\t\tResidue: %s\n", str);
+                    tng_residue_num_atoms_get(input, residue, &nAtoms);
+                    for (gmx_int64_t l = 0; l < nAtoms; l++)
+                    {
+                        tng_residue_atom_of_index_get(input, residue, l, &atom);
+                        tng_atom_name_get(input, atom, str, 256);
+                        fprintf(stream, "\t\t\tAtom: %s", str);
+                        tng_atom_type_get(input, atom, str, 256);
+                        fprintf(stream, " (%s)\n", str);
+                    }
+                }
+            }
+        }
+        /* It is possible to have a molecule without chains, in which case
+         * residues in the molecule can be iterated through without going
+         * through chains. */
+        else
+        {
+            tng_molecule_num_residues_get(input, molecule, &nResidues);
+            if (nResidues > 0)
+            {
+                for (gmx_int64_t k = 0; k < nResidues; k++)
+                {
+                    tng_molecule_residue_of_index_get(input, molecule, k, &residue);
+                    tng_residue_name_get(input, residue, str, 256);
+                    fprintf(stream, "\t\tResidue: %s\n", str);
+                    tng_residue_num_atoms_get(input, residue, &nAtoms);
+                    for (gmx_int64_t l = 0; l < nAtoms; l++)
+                    {
+                        tng_residue_atom_of_index_get(input, residue, l, &atom);
+                        tng_atom_name_get(input, atom, str, 256);
+                        fprintf(stream, "\t\t\tAtom: %s", str);
+                        tng_atom_type_get(input, atom, str, 256);
+                        fprintf(stream, " (%s)\n", str);
+                    }
+                }
+            }
+            else
+            {
+                tng_molecule_num_atoms_get(input, molecule, &nAtoms);
+                for (gmx_int64_t l = 0; l < nAtoms; l++)
+                {
+                    tng_molecule_atom_of_index_get(input, molecule, l, &atom);
+                    tng_atom_name_get(input, atom, str, 256);
+                    fprintf(stream, "\t\t\tAtom: %s", str);
+                    tng_atom_type_get(input, atom, str, 256);
+                    fprintf(stream, " (%s)\n", str);
+                }
+            }
+        }
+    }
+#else
+    GMX_UNUSED_VALUE(input);
+    GMX_UNUSED_VALUE(stream);
+#endif
+}
+
+gmx_bool gmx_get_tng_data_block_types_of_next_frame(tng_trajectory_t     input,
+                                                    int                  frame,
+                                                    int                  nRequestedIds,
+                                                    gmx_int64_t         *requestedIds,
+                                                    gmx_int64_t         *nextFrame,
+                                                    gmx_int64_t         *nBlocks,
+                                                    gmx_int64_t        **blockIds)
+{
+#if GMX_USE_TNG
+    tng_function_status stat;
+
+    stat = tng_util_trajectory_next_frame_present_data_blocks_find(input, frame,
+                                                                   nRequestedIds, requestedIds,
+                                                                   nextFrame,
+                                                                   nBlocks, blockIds);
+
+    if (stat == TNG_CRITICAL)
+    {
+        gmx_file("Cannot read TNG file. Cannot find data blocks of next frame.");
+    }
+    else if (stat == TNG_FAILURE)
+    {
+        return FALSE;
+    }
+    return TRUE;
+#else
+    GMX_UNUSED_VALUE(input);
+    GMX_UNUSED_VALUE(frame);
+    GMX_UNUSED_VALUE(nRequestedIds);
+    GMX_UNUSED_VALUE(requestedIds);
+    GMX_UNUSED_VALUE(nextFrame);
+    GMX_UNUSED_VALUE(nBlocks);
+    GMX_UNUSED_VALUE(blockIds);
+    return FALSE;
+#endif
+}
+
+gmx_bool gmx_get_tng_data_next_frame_of_block_type(tng_trajectory_t     input,
+                                                   gmx_int64_t          blockId,
+                                                   real               **values,
+                                                   gmx_int64_t         *frameNumber,
+                                                   double              *frameTime,
+                                                   gmx_int64_t         *nValuesPerFrame,
+                                                   gmx_int64_t         *nAtoms,
+                                                   real                *prec,
+                                                   char                *name,
+                                                   int                  maxLen,
+                                                   gmx_bool            *bOK)
+{
+#if GMX_USE_TNG
+    tng_function_status stat;
+    char                datatype = -1;
+    gmx_int64_t         codecId;
+    int                 blockDependency;
+    void               *data = 0;
+    double              localPrec;
+
+    stat = tng_data_block_name_get(input, blockId, name, maxLen);
+    if (stat != TNG_SUCCESS)
+    {
+        gmx_file("Cannot read next frame of TNG file");
+    }
+    stat = tng_data_block_dependency_get(input, blockId, &blockDependency);
+    if (stat != TNG_SUCCESS)
+    {
+        gmx_file("Cannot read next frame of TNG file");
+    }
+    if (blockDependency & TNG_PARTICLE_DEPENDENT)
+    {
+        tng_num_particles_get(input, nAtoms);
+        stat = tng_util_particle_data_next_frame_read(input,
+                                                      blockId,
+                                                      &data,
+                                                      &datatype,
+                                                      frameNumber,
+                                                      frameTime);
+    }
+    else
+    {
+        *nAtoms = 1; /* There are not actually any atoms, but it is used for
+                        allocating memory */
+        stat    = tng_util_non_particle_data_next_frame_read(input,
+                                                             blockId,
+                                                             &data,
+                                                             &datatype,
+                                                             frameNumber,
+                                                             frameTime);
+    }
+    if (stat == TNG_CRITICAL)
+    {
+        gmx_file("Cannot read next frame of TNG file");
+    }
+    if (stat == TNG_FAILURE)
+    {
+        *bOK = TRUE;
+        return FALSE;
+    }
+
+    stat = tng_data_block_num_values_per_frame_get(input, blockId, nValuesPerFrame);
+    if (stat != TNG_SUCCESS)
+    {
+        gmx_file("Cannot read next frame of TNG file");
+    }
+    srenew(*values, sizeof(real) * *nValuesPerFrame * *nAtoms);
+    convert_array_to_real_array(data,
+                                *values,
+                                getDistanceScaleFactor(input),
+                                *nAtoms,
+                                *nValuesPerFrame,
+                                datatype);
+
+    tng_util_frame_current_compression_get(input, blockId, &codecId, &localPrec);
+
+    /* This must be updated if/when more lossy compression methods are added */
+    if (codecId != TNG_TNG_COMPRESSION)
+    {
+        *prec = -1.0;
+    }
+    else
+    {
+        *prec = localPrec;
+    }
+
+    *bOK = TRUE;
+    return TRUE;
+#else
+    GMX_UNUSED_VALUE(input);
+    GMX_UNUSED_VALUE(blockId);
+    GMX_UNUSED_VALUE(values);
+    GMX_UNUSED_VALUE(frameNumber);
+    GMX_UNUSED_VALUE(frameTime);
+    GMX_UNUSED_VALUE(nValuesPerFrame);
+    GMX_UNUSED_VALUE(nAtoms);
+    GMX_UNUSED_VALUE(prec);
+    GMX_UNUSED_VALUE(name);
+    GMX_UNUSED_VALUE(maxLen);
+    GMX_UNUSED_VALUE(bOK);
+    return FALSE;
+#endif
+}
index 544ad46b0eba333c9897345faa012e6a288b8e08..4881f2d8d9c4a0d463546e8fe3a0d7426da80869 100644 (file)
@@ -36,7 +36,7 @@
 #ifndef GMX_FILEIO_TNGIO_H
 #define GMX_FILEIO_TNGIO_H
 
-#include "tng/tng_io_fwd.h"
+#include <cstdio>
 
 #include "gromacs/math/vectypes.h"
 #include "gromacs/utility/basedefinitions.h"
@@ -44,6 +44,9 @@
 
 struct gmx_mtop_t;
 struct t_inputrec;
+struct tng_trajectory;
+typedef struct tng_trajectory *tng_trajectory_t;
+struct t_trxframe;
 
 /*! \brief Open a TNG trajectory file
  *
@@ -138,4 +141,69 @@ void fflush_tng(tng_trajectory_t tng);
  */
 float gmx_tng_get_time_of_final_frame(tng_trajectory_t tng);
 
+/*! \brief Prepare to write TNG output from trajectory conversion tools */
+void gmx_prepare_tng_writing(const char              *filename,
+                             char                     mode,
+                             tng_trajectory_t        *in,
+                             tng_trajectory_t        *out,
+                             int                      nAtoms,
+                             const struct gmx_mtop_t *mtop,
+                             const int               *index,
+                             const char              *indexGroupName);
+
+/*! \brief Write a trxframe to a TNG file
+ *
+ * \param output Trajectory to write to
+ * \param frame  Frame data to write
+ * \param natoms Number of atoms to actually write
+ *
+ * The natoms field in frame is the number of atoms in the system. The
+ * parameter natoms supports writing an index-group subset of the
+ * atoms.
+ */
+void gmx_write_tng_from_trxframe(tng_trajectory_t        output,
+                                 const t_trxframe       *frame,
+                                 int                     natoms);
+
+/*! \brief Creates a molecule containing only the indexed atoms and sets
+ * the number of all other molecules to 0. Works similar to a
+ * selection group. */
+void gmx_tng_setup_atom_subgroup(tng_trajectory_t tng,
+                                 const int        nind,
+                                 const int       *ind,
+                                 const char      *name);
+
+/*! \brief Read the first/next TNG frame. */
+gmx_bool gmx_read_next_tng_frame(tng_trajectory_t            input,
+                                 struct t_trxframe          *fr,
+                                 gmx_int64_t                *requestedIds,
+                                 int                         numRequestedIds);
+
+/*! \brief Print the molecule system to stream */
+void gmx_print_tng_molecule_system(tng_trajectory_t input,
+                                   FILE            *stream);
+
+/*! \brief Get a list of block IDs present in the next frame with data. */
+gmx_bool gmx_get_tng_data_block_types_of_next_frame(tng_trajectory_t     input,
+                                                    int                  frame,
+                                                    int                  nRequestedIds,
+                                                    gmx_int64_t         *requestedIds,
+                                                    gmx_int64_t         *nextFrame,
+                                                    gmx_int64_t         *nBlocks,
+                                                    gmx_int64_t        **blockIds);
+
+/*! \brief Get data of the next frame with data from the data block
+ * with the specified block ID. */
+gmx_bool gmx_get_tng_data_next_frame_of_block_type(tng_trajectory_t     input,
+                                                   gmx_int64_t          blockId,
+                                                   real               **values,
+                                                   gmx_int64_t         *frameNumber,
+                                                   double              *frameTime,
+                                                   gmx_int64_t         *nValuesPerFrame,
+                                                   gmx_int64_t         *nAtoms,
+                                                   real                *prec,
+                                                   char                *name,
+                                                   int                  maxLen,
+                                                   gmx_bool            *bOK);
+
 #endif /* GMX_FILEIO_TNGIO_H */
diff --git a/src/gromacs/fileio/tngio_for_tools.cpp b/src/gromacs/fileio/tngio_for_tools.cpp
deleted file mode 100644 (file)
index 51839aa..0000000
+++ /dev/null
@@ -1,879 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
- * and including many others, as listed in the AUTHORS file in the
- * top-level source directory and at http://www.gromacs.org.
- *
- * GROMACS is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * GROMACS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with GROMACS; if not, see
- * http://www.gnu.org/licenses, or write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
- *
- * If you want to redistribute modifications to GROMACS, please
- * consider that scientific software is very special. Version
- * control is crucial - bugs must be traceable. We will be happy to
- * consider code for inclusion in the official distribution, but
- * derived work must not be called official GROMACS. Details are found
- * in the README & COPYING files - if they are missing, get the
- * official version at http://www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the research papers on the package. Check out http://www.gromacs.org.
- */
-#include "gmxpre.h"
-
-#include "tngio_for_tools.h"
-
-#include "config.h"
-
-#include <cmath>
-
-#if GMX_USE_TNG
-#include "tng/tng_io.h"
-#endif
-
-#include "gromacs/fileio/tngio.h"
-#include "gromacs/math/units.h"
-#include "gromacs/trajectory/trajectoryframe.h"
-#include "gromacs/utility/basedefinitions.h"
-#include "gromacs/utility/fatalerror.h"
-#include "gromacs/utility/smalloc.h"
-
-void gmx_prepare_tng_writing(const char              *filename,
-                             char                     mode,
-                             tng_trajectory_t        *input,
-                             tng_trajectory_t        *output,
-                             int                      nAtoms,
-                             const gmx_mtop_t        *mtop,
-                             const int               *index,
-                             const char              *indexGroupName)
-{
-#if GMX_USE_TNG
-    /* FIXME after 5.0: Currently only standard block types are read */
-    const int           defaultNumIds              = 5;
-    static gmx_int64_t  fallbackIds[defaultNumIds] =
-    {
-        TNG_TRAJ_BOX_SHAPE, TNG_TRAJ_POSITIONS,
-        TNG_TRAJ_VELOCITIES, TNG_TRAJ_FORCES,
-        TNG_GMX_LAMBDA
-    };
-    static char         fallbackNames[defaultNumIds][32] =
-    {
-        "BOX SHAPE", "POSITIONS", "VELOCITIES",
-        "FORCES", "LAMBDAS"
-    };
-
-    typedef tng_function_status (*set_writing_interval_func_pointer)(tng_trajectory_t,
-                                                                     const gmx_int64_t,
-                                                                     const gmx_int64_t,
-                                                                     const gmx_int64_t,
-                                                                     const char*,
-                                                                     const char,
-                                                                     const char);
-#if GMX_DOUBLE
-    set_writing_interval_func_pointer set_writing_interval = tng_util_generic_write_interval_double_set;
-#else
-    set_writing_interval_func_pointer set_writing_interval = tng_util_generic_write_interval_set;
-#endif
-
-    gmx_tng_open(filename, mode, output);
-
-    /* Do we have an input file in TNG format? If so, then there's
-       more data we can copy over, rather than having to improvise. */
-    if (*input)
-    {
-        /* Set parameters (compression, time per frame, molecule
-         * information, number of frames per frame set and writing
-         * intervals of positions, box shape and lambdas) of the
-         * output tng container based on their respective values int
-         * the input tng container */
-        double      time, compression_precision;
-        gmx_int64_t n_frames_per_frame_set, interval = -1;
-
-        tng_compression_precision_get(*input, &compression_precision);
-        tng_compression_precision_set(*output, compression_precision);
-        // TODO make this configurable in a future version
-        char compression_type = TNG_TNG_COMPRESSION;
-
-        tng_molecule_system_copy(*input, *output);
-
-        tng_time_per_frame_get(*input, &time);
-        tng_time_per_frame_set(*output, time);
-
-        tng_num_frames_per_frame_set_get(*input, &n_frames_per_frame_set);
-        tng_num_frames_per_frame_set_set(*output, n_frames_per_frame_set);
-
-        for (int i = 0; i < defaultNumIds; i++)
-        {
-            if (tng_data_get_stride_length(*input, fallbackIds[i], -1, &interval)
-                == TNG_SUCCESS)
-            {
-                switch (fallbackIds[i])
-                {
-                    case TNG_TRAJ_POSITIONS:
-                    case TNG_TRAJ_VELOCITIES:
-                        set_writing_interval(*output, interval, 3, fallbackIds[i],
-                                             fallbackNames[i], TNG_PARTICLE_BLOCK_DATA,
-                                             compression_type);
-                        break;
-                    case TNG_TRAJ_FORCES:
-                        set_writing_interval(*output, interval, 3, fallbackIds[i],
-                                             fallbackNames[i], TNG_PARTICLE_BLOCK_DATA,
-                                             TNG_GZIP_COMPRESSION);
-                        break;
-                    case TNG_TRAJ_BOX_SHAPE:
-                        set_writing_interval(*output, interval, 9, fallbackIds[i],
-                                             fallbackNames[i], TNG_NON_PARTICLE_BLOCK_DATA,
-                                             TNG_GZIP_COMPRESSION);
-                        break;
-                    case TNG_GMX_LAMBDA:
-                        set_writing_interval(*output, interval, 1, fallbackIds[i],
-                                             fallbackNames[i], TNG_NON_PARTICLE_BLOCK_DATA,
-                                             TNG_GZIP_COMPRESSION);
-                    default:
-                        continue;
-                }
-            }
-        }
-
-    }
-    else
-    {
-        /* TODO after trjconv is modularized: fix this so the user can
-           change precision when they are doing an operation where
-           this makes sense, and not otherwise.
-
-           char compression = bUseLossyCompression ? TNG_TNG_COMPRESSION : TNG_GZIP_COMPRESSION;
-           gmx_tng_set_compression_precision(*output, ndec2prec(nDecimalsOfPrecision));
-         */
-        gmx_tng_add_mtop(*output, mtop);
-        tng_num_frames_per_frame_set_set(*output, 1);
-    }
-
-    if (index && nAtoms > 0)
-    {
-        gmx_tng_setup_atom_subgroup(*output, nAtoms, index, indexGroupName);
-    }
-
-    /* If for some reason there are more requested atoms than there are atoms in the
-     * molecular system create a number of implicit atoms (without atom data) to
-     * compensate for that. */
-    if (nAtoms >= 0)
-    {
-        tng_implicit_num_particles_set(*output, nAtoms);
-    }
-#else
-    GMX_UNUSED_VALUE(filename);
-    GMX_UNUSED_VALUE(mode);
-    GMX_UNUSED_VALUE(input);
-    GMX_UNUSED_VALUE(output);
-    GMX_UNUSED_VALUE(nAtoms);
-    GMX_UNUSED_VALUE(mtop);
-    GMX_UNUSED_VALUE(index);
-    GMX_UNUSED_VALUE(indexGroupName);
-#endif
-}
-
-void gmx_write_tng_from_trxframe(tng_trajectory_t        output,
-                                 const t_trxframe       *frame,
-                                 int                     natoms)
-{
-#if GMX_USE_TNG
-    if (frame->step > 0)
-    {
-        double timePerFrame = frame->time * PICO / frame->step;
-        tng_time_per_frame_set(output, timePerFrame);
-    }
-    if (natoms < 0)
-    {
-        natoms = frame->natoms;
-    }
-    gmx_fwrite_tng(output,
-                   TRUE,
-                   frame->step,
-                   frame->time,
-                   0,
-                   frame->box,
-                   natoms,
-                   frame->x,
-                   frame->v,
-                   frame->f);
-#else
-    GMX_UNUSED_VALUE(output);
-    GMX_UNUSED_VALUE(frame);
-    GMX_UNUSED_VALUE(natoms);
-#endif
-}
-
-#if GMX_USE_TNG
-static void
-convert_array_to_real_array(void       *from,
-                            real       *to,
-                            const float fact,
-                            const int   nAtoms,
-                            const int   nValues,
-                            const char  datatype)
-{
-    int        i, j;
-
-    const bool useDouble = GMX_DOUBLE;
-    switch (datatype)
-    {
-        case TNG_FLOAT_DATA:
-            if (!useDouble)
-            {
-                if (fact == 1)
-                {
-                    memcpy(to, from, nValues * sizeof(real) * nAtoms);
-                }
-                else
-                {
-                    for (i = 0; i < nAtoms; i++)
-                    {
-                        for (j = 0; j < nValues; j++)
-                        {
-                            to[i*nValues+j] = reinterpret_cast<float *>(from)[i*nValues+j] * fact;
-                        }
-                    }
-                }
-            }
-            else
-            {
-                for (i = 0; i < nAtoms; i++)
-                {
-                    for (j = 0; j < nValues; j++)
-                    {
-                        to[i*nValues+j] = reinterpret_cast<float *>(from)[i*nValues+j] * fact;
-                    }
-                }
-            }
-            break;
-        case TNG_INT_DATA:
-            for (i = 0; i < nAtoms; i++)
-            {
-                for (j = 0; j < nValues; j++)
-                {
-                    to[i*nValues+j] = reinterpret_cast<gmx_int64_t *>(from)[i*nValues+j] * fact;
-                }
-            }
-            break;
-        case TNG_DOUBLE_DATA:
-            if (sizeof(real) == sizeof(double))
-            {
-                if (fact == 1)
-                {
-                    memcpy(to, from, nValues * sizeof(real) * nAtoms);
-                }
-                else
-                {
-                    for (i = 0; i < nAtoms; i++)
-                    {
-                        for (j = 0; j < nValues; j++)
-                        {
-                            to[i*nValues+j] = reinterpret_cast<double *>(from)[i*nValues+j] * fact;
-                        }
-                    }
-                }
-            }
-            else
-            {
-                for (i = 0; i < nAtoms; i++)
-                {
-                    for (j = 0; j < nValues; j++)
-                    {
-                        to[i*nValues+j] = reinterpret_cast<double *>(from)[i*nValues+j] * fact;
-                    }
-                }
-            }
-            break;
-        default:
-            gmx_incons("Illegal datatype when converting values to a real array!");
-            return;
-    }
-    return;
-}
-
-static real getDistanceScaleFactor(tng_trajectory_t in)
-{
-    gmx_int64_t exp = -1;
-    real        distanceScaleFactor;
-
-    // TODO Hopefully, TNG 2.0 will do this kind of thing for us
-    tng_distance_unit_exponential_get(in, &exp);
-
-    // GROMACS expects distances in nm
-    switch (exp)
-    {
-        case 9:
-            distanceScaleFactor = NANO/NANO;
-            break;
-        case 10:
-            distanceScaleFactor = NANO/ANGSTROM;
-            break;
-        default:
-            distanceScaleFactor = pow(10.0, exp + 9.0);
-    }
-
-    return distanceScaleFactor;
-}
-#endif
-
-void gmx_tng_setup_atom_subgroup(tng_trajectory_t tng,
-                                 const int        nind,
-                                 const int       *ind,
-                                 const char      *name)
-{
-#if GMX_USE_TNG
-    gmx_int64_t              nAtoms, cnt, nMols;
-    tng_molecule_t           mol, iterMol;
-    tng_chain_t              chain;
-    tng_residue_t            res;
-    tng_atom_t               atom;
-    tng_function_status      stat;
-
-    tng_num_particles_get(tng, &nAtoms);
-
-    if (nAtoms == nind)
-    {
-        return;
-    }
-
-    stat = tng_molecule_find(tng, name, -1, &mol);
-    if (stat == TNG_SUCCESS)
-    {
-        tng_molecule_num_atoms_get(tng, mol, &nAtoms);
-        tng_molecule_cnt_get(tng, mol, &cnt);
-        if (nAtoms == nind)
-        {
-            stat = TNG_SUCCESS;
-        }
-        else
-        {
-            stat = TNG_FAILURE;
-        }
-    }
-    if (stat == TNG_FAILURE)
-    {
-        /* The indexed atoms are added to one separate molecule. */
-        tng_molecule_alloc(tng, &mol);
-        tng_molecule_name_set(tng, mol, name);
-        tng_molecule_chain_add(tng, mol, "", &chain);
-
-        for (int i = 0; i < nind; i++)
-        {
-            char        temp_name[256], temp_type[256];
-
-            /* Try to retrieve the residue name of the atom */
-            stat = tng_residue_name_of_particle_nr_get(tng, ind[i], temp_name, 256);
-            if (stat != TNG_SUCCESS)
-            {
-                temp_name[0] = '\0';
-            }
-            /* Check if the molecule of the selection already contains this residue */
-            if (tng_chain_residue_find(tng, chain, temp_name, -1, &res)
-                != TNG_SUCCESS)
-            {
-                tng_chain_residue_add(tng, chain, temp_name, &res);
-            }
-            /* Try to find the original name and type of the atom */
-            stat = tng_atom_name_of_particle_nr_get(tng, ind[i], temp_name, 256);
-            if (stat != TNG_SUCCESS)
-            {
-                temp_name[0] = '\0';
-            }
-            stat = tng_atom_type_of_particle_nr_get(tng, ind[i], temp_type, 256);
-            if (stat != TNG_SUCCESS)
-            {
-                temp_type[0] = '\0';
-            }
-            tng_residue_atom_w_id_add(tng, res, temp_name, temp_type, ind[i], &atom);
-        }
-        tng_molecule_existing_add(tng, &mol);
-    }
-    /* Set the count of the molecule containing the selected atoms to 1 and all
-     * other molecules to 0 */
-    tng_molecule_cnt_set(tng, mol, 1);
-    tng_num_molecule_types_get(tng, &nMols);
-    for (gmx_int64_t k = 0; k < nMols; k++)
-    {
-        tng_molecule_of_index_get(tng, k, &iterMol);
-        if (iterMol == mol)
-        {
-            continue;
-        }
-        tng_molecule_cnt_set(tng, iterMol, 0);
-    }
-#else
-    GMX_UNUSED_VALUE(tng);
-    GMX_UNUSED_VALUE(nind);
-    GMX_UNUSED_VALUE(ind);
-    GMX_UNUSED_VALUE(name);
-#endif
-}
-
-/* TODO: If/when TNG acquires the ability to copy data blocks without
- * uncompressing them, then this implemenation should be reconsidered.
- * Ideally, gmx trjconv -f a.tng -o b.tng -b 10 -e 20 would be fast
- * and lose no information. */
-gmx_bool gmx_read_next_tng_frame(tng_trajectory_t            input,
-                                 t_trxframe                 *fr,
-                                 gmx_int64_t                *requestedIds,
-                                 int                         numRequestedIds)
-{
-#if GMX_USE_TNG
-    gmx_bool                bOK = TRUE;
-    tng_function_status     stat;
-    gmx_int64_t             numberOfAtoms = -1, frameNumber = -1;
-    gmx_int64_t             nBlocks, blockId, *blockIds = NULL, codecId;
-    char                    datatype      = -1;
-    void                   *values        = NULL;
-    double                  frameTime     = -1.0;
-    int                     size, blockDependency;
-    double                  prec;
-    const int               defaultNumIds = 5;
-    static gmx_int64_t      fallbackRequestedIds[defaultNumIds] =
-    {
-        TNG_TRAJ_BOX_SHAPE, TNG_TRAJ_POSITIONS,
-        TNG_TRAJ_VELOCITIES, TNG_TRAJ_FORCES,
-        TNG_GMX_LAMBDA
-    };
-
-
-    fr->bStep     = FALSE;
-    fr->bTime     = FALSE;
-    fr->bLambda   = FALSE;
-    fr->bAtoms    = FALSE;
-    fr->bPrec     = FALSE;
-    fr->bX        = FALSE;
-    fr->bV        = FALSE;
-    fr->bF        = FALSE;
-    fr->bBox      = FALSE;
-
-    /* If no specific IDs were requested read all block types that can
-     * currently be interpreted */
-    if (!requestedIds || numRequestedIds == 0)
-    {
-        numRequestedIds = defaultNumIds;
-        requestedIds    = fallbackRequestedIds;
-    }
-
-    stat = tng_num_particles_get(input, &numberOfAtoms);
-    if (stat != TNG_SUCCESS)
-    {
-        gmx_file("Cannot determine number of atoms from TNG file.");
-    }
-    fr->natoms = numberOfAtoms;
-
-    if (!gmx_get_tng_data_block_types_of_next_frame(input,
-                                                    fr->step,
-                                                    numRequestedIds,
-                                                    requestedIds,
-                                                    &frameNumber,
-                                                    &nBlocks,
-                                                    &blockIds))
-    {
-        return FALSE;
-    }
-
-    if (nBlocks == 0)
-    {
-        return FALSE;
-    }
-
-    for (gmx_int64_t i = 0; i < nBlocks; i++)
-    {
-        blockId = blockIds[i];
-        tng_data_block_dependency_get(input, blockId, &blockDependency);
-        if (blockDependency & TNG_PARTICLE_DEPENDENT)
-        {
-            stat = tng_util_particle_data_next_frame_read(input,
-                                                          blockId,
-                                                          &values,
-                                                          &datatype,
-                                                          &frameNumber,
-                                                          &frameTime);
-        }
-        else
-        {
-            stat = tng_util_non_particle_data_next_frame_read(input,
-                                                              blockId,
-                                                              &values,
-                                                              &datatype,
-                                                              &frameNumber,
-                                                              &frameTime);
-        }
-        if (stat == TNG_CRITICAL)
-        {
-            gmx_file("Cannot read positions from TNG file.");
-            return FALSE;
-        }
-        else if (stat == TNG_FAILURE)
-        {
-            continue;
-        }
-        switch (blockId)
-        {
-            case TNG_TRAJ_BOX_SHAPE:
-                switch (datatype)
-                {
-                    case TNG_INT_DATA:
-                        size = sizeof(gmx_int64_t);
-                        break;
-                    case TNG_FLOAT_DATA:
-                        size = sizeof(float);
-                        break;
-                    case TNG_DOUBLE_DATA:
-                        size = sizeof(double);
-                        break;
-                    default:
-                        gmx_incons("Illegal datatype of box shape values!");
-                }
-                for (int i = 0; i < DIM; i++)
-                {
-                    convert_array_to_real_array(reinterpret_cast<char *>(values) + size * i * DIM,
-                                                reinterpret_cast<real *>(fr->box[i]),
-                                                getDistanceScaleFactor(input),
-                                                1,
-                                                DIM,
-                                                datatype);
-                }
-                fr->bBox = TRUE;
-                break;
-            case TNG_TRAJ_POSITIONS:
-                srenew(fr->x, fr->natoms);
-                convert_array_to_real_array(values,
-                                            reinterpret_cast<real *>(fr->x),
-                                            getDistanceScaleFactor(input),
-                                            fr->natoms,
-                                            DIM,
-                                            datatype);
-                fr->bX = TRUE;
-                tng_util_frame_current_compression_get(input, blockId, &codecId, &prec);
-                /* This must be updated if/when more lossy compression methods are added */
-                if (codecId == TNG_TNG_COMPRESSION)
-                {
-                    fr->prec  = prec;
-                    fr->bPrec = TRUE;
-                }
-                break;
-            case TNG_TRAJ_VELOCITIES:
-                srenew(fr->v, fr->natoms);
-                convert_array_to_real_array(values,
-                                            (real *) fr->v,
-                                            getDistanceScaleFactor(input),
-                                            fr->natoms,
-                                            DIM,
-                                            datatype);
-                fr->bV = TRUE;
-                tng_util_frame_current_compression_get(input, blockId, &codecId, &prec);
-                /* This must be updated if/when more lossy compression methods are added */
-                if (codecId == TNG_TNG_COMPRESSION)
-                {
-                    fr->prec  = prec;
-                    fr->bPrec = TRUE;
-                }
-                break;
-            case TNG_TRAJ_FORCES:
-                srenew(fr->f, fr->natoms);
-                convert_array_to_real_array(values,
-                                            reinterpret_cast<real *>(fr->f),
-                                            getDistanceScaleFactor(input),
-                                            fr->natoms,
-                                            DIM,
-                                            datatype);
-                fr->bF = TRUE;
-                break;
-            case TNG_GMX_LAMBDA:
-                switch (datatype)
-                {
-                    case TNG_FLOAT_DATA:
-                        fr->lambda = *(reinterpret_cast<float *>(values));
-                        break;
-                    case TNG_DOUBLE_DATA:
-                        fr->lambda = *(reinterpret_cast<double *>(values));
-                        break;
-                    default:
-                        gmx_incons("Illegal datatype lambda value!");
-                }
-                fr->bLambda = TRUE;
-                break;
-            default:
-                gmx_warning("Illegal block type! Currently GROMACS tools can only handle certain data types. Skipping block.");
-        }
-        /* values does not have to be freed before reading next frame. It will
-         * be reallocated if it is not NULL. */
-    }
-
-    fr->step  = frameNumber;
-    fr->bStep = TRUE;
-    // Convert the time to ps
-    fr->time  = frameTime / PICO;
-    fr->bTime = TRUE;
-
-    /* values must be freed before leaving this function */
-    sfree(values);
-
-    return bOK;
-#else
-    GMX_UNUSED_VALUE(input);
-    GMX_UNUSED_VALUE(fr);
-    GMX_UNUSED_VALUE(requestedIds);
-    GMX_UNUSED_VALUE(numRequestedIds);
-    return FALSE;
-#endif
-}
-
-void gmx_print_tng_molecule_system(tng_trajectory_t input,
-                                   FILE            *stream)
-{
-#if GMX_USE_TNG
-    gmx_int64_t        nMolecules, nChains, nResidues, nAtoms, *molCntList;
-    tng_molecule_t     molecule;
-    tng_chain_t        chain;
-    tng_residue_t      residue;
-    tng_atom_t         atom;
-    char               str[256], varNAtoms;
-
-    tng_num_molecule_types_get(input, &nMolecules);
-    tng_molecule_cnt_list_get(input, &molCntList);
-    /* Can the number of particles change in the trajectory or is it constant? */
-    tng_num_particles_variable_get(input, &varNAtoms);
-
-    for (gmx_int64_t i = 0; i < nMolecules; i++)
-    {
-        tng_molecule_of_index_get(input, i, &molecule);
-        tng_molecule_name_get(input, molecule, str, 256);
-        if (varNAtoms == TNG_CONSTANT_N_ATOMS)
-        {
-            if ((int)molCntList[i] == 0)
-            {
-                continue;
-            }
-            fprintf(stream, "Molecule: %s, count: %d\n", str, (int)molCntList[i]);
-        }
-        else
-        {
-            fprintf(stream, "Molecule: %s\n", str);
-        }
-        tng_molecule_num_chains_get(input, molecule, &nChains);
-        if (nChains > 0)
-        {
-            for (gmx_int64_t j = 0; j < nChains; j++)
-            {
-                tng_molecule_chain_of_index_get(input, molecule, j, &chain);
-                tng_chain_name_get(input, chain, str, 256);
-                fprintf(stream, "\tChain: %s\n", str);
-                tng_chain_num_residues_get(input, chain, &nResidues);
-                for (gmx_int64_t k = 0; k < nResidues; k++)
-                {
-                    tng_chain_residue_of_index_get(input, chain, k, &residue);
-                    tng_residue_name_get(input, residue, str, 256);
-                    fprintf(stream, "\t\tResidue: %s\n", str);
-                    tng_residue_num_atoms_get(input, residue, &nAtoms);
-                    for (gmx_int64_t l = 0; l < nAtoms; l++)
-                    {
-                        tng_residue_atom_of_index_get(input, residue, l, &atom);
-                        tng_atom_name_get(input, atom, str, 256);
-                        fprintf(stream, "\t\t\tAtom: %s", str);
-                        tng_atom_type_get(input, atom, str, 256);
-                        fprintf(stream, " (%s)\n", str);
-                    }
-                }
-            }
-        }
-        /* It is possible to have a molecule without chains, in which case
-         * residues in the molecule can be iterated through without going
-         * through chains. */
-        else
-        {
-            tng_molecule_num_residues_get(input, molecule, &nResidues);
-            if (nResidues > 0)
-            {
-                for (gmx_int64_t k = 0; k < nResidues; k++)
-                {
-                    tng_molecule_residue_of_index_get(input, molecule, k, &residue);
-                    tng_residue_name_get(input, residue, str, 256);
-                    fprintf(stream, "\t\tResidue: %s\n", str);
-                    tng_residue_num_atoms_get(input, residue, &nAtoms);
-                    for (gmx_int64_t l = 0; l < nAtoms; l++)
-                    {
-                        tng_residue_atom_of_index_get(input, residue, l, &atom);
-                        tng_atom_name_get(input, atom, str, 256);
-                        fprintf(stream, "\t\t\tAtom: %s", str);
-                        tng_atom_type_get(input, atom, str, 256);
-                        fprintf(stream, " (%s)\n", str);
-                    }
-                }
-            }
-            else
-            {
-                tng_molecule_num_atoms_get(input, molecule, &nAtoms);
-                for (gmx_int64_t l = 0; l < nAtoms; l++)
-                {
-                    tng_molecule_atom_of_index_get(input, molecule, l, &atom);
-                    tng_atom_name_get(input, atom, str, 256);
-                    fprintf(stream, "\t\t\tAtom: %s", str);
-                    tng_atom_type_get(input, atom, str, 256);
-                    fprintf(stream, " (%s)\n", str);
-                }
-            }
-        }
-    }
-#else
-    GMX_UNUSED_VALUE(input);
-    GMX_UNUSED_VALUE(stream);
-#endif
-}
-
-gmx_bool gmx_get_tng_data_block_types_of_next_frame(tng_trajectory_t     input,
-                                                    int                  frame,
-                                                    int                  nRequestedIds,
-                                                    gmx_int64_t         *requestedIds,
-                                                    gmx_int64_t         *nextFrame,
-                                                    gmx_int64_t         *nBlocks,
-                                                    gmx_int64_t        **blockIds)
-{
-#if GMX_USE_TNG
-    tng_function_status stat;
-
-    stat = tng_util_trajectory_next_frame_present_data_blocks_find(input, frame,
-                                                                   nRequestedIds, requestedIds,
-                                                                   nextFrame,
-                                                                   nBlocks, blockIds);
-
-    if (stat == TNG_CRITICAL)
-    {
-        gmx_file("Cannot read TNG file. Cannot find data blocks of next frame.");
-    }
-    else if (stat == TNG_FAILURE)
-    {
-        return FALSE;
-    }
-    return TRUE;
-#else
-    GMX_UNUSED_VALUE(input);
-    GMX_UNUSED_VALUE(frame);
-    GMX_UNUSED_VALUE(nRequestedIds);
-    GMX_UNUSED_VALUE(requestedIds);
-    GMX_UNUSED_VALUE(nextFrame);
-    GMX_UNUSED_VALUE(nBlocks);
-    GMX_UNUSED_VALUE(blockIds);
-    return FALSE;
-#endif
-}
-
-gmx_bool gmx_get_tng_data_next_frame_of_block_type(tng_trajectory_t     input,
-                                                   gmx_int64_t          blockId,
-                                                   real               **values,
-                                                   gmx_int64_t         *frameNumber,
-                                                   double              *frameTime,
-                                                   gmx_int64_t         *nValuesPerFrame,
-                                                   gmx_int64_t         *nAtoms,
-                                                   real                *prec,
-                                                   char                *name,
-                                                   int                  maxLen,
-                                                   gmx_bool            *bOK)
-{
-#if GMX_USE_TNG
-    tng_function_status stat;
-    char                datatype = -1;
-    gmx_int64_t         codecId;
-    int                 blockDependency;
-    void               *data = 0;
-    double              localPrec;
-
-    stat = tng_data_block_name_get(input, blockId, name, maxLen);
-    if (stat != TNG_SUCCESS)
-    {
-        gmx_file("Cannot read next frame of TNG file");
-    }
-    stat = tng_data_block_dependency_get(input, blockId, &blockDependency);
-    if (stat != TNG_SUCCESS)
-    {
-        gmx_file("Cannot read next frame of TNG file");
-    }
-    if (blockDependency & TNG_PARTICLE_DEPENDENT)
-    {
-        tng_num_particles_get(input, nAtoms);
-        stat = tng_util_particle_data_next_frame_read(input,
-                                                      blockId,
-                                                      &data,
-                                                      &datatype,
-                                                      frameNumber,
-                                                      frameTime);
-    }
-    else
-    {
-        *nAtoms = 1; /* There are not actually any atoms, but it is used for
-                        allocating memory */
-        stat    = tng_util_non_particle_data_next_frame_read(input,
-                                                             blockId,
-                                                             &data,
-                                                             &datatype,
-                                                             frameNumber,
-                                                             frameTime);
-    }
-    if (stat == TNG_CRITICAL)
-    {
-        gmx_file("Cannot read next frame of TNG file");
-    }
-    if (stat == TNG_FAILURE)
-    {
-        *bOK = TRUE;
-        return FALSE;
-    }
-
-    stat = tng_data_block_num_values_per_frame_get(input, blockId, nValuesPerFrame);
-    if (stat != TNG_SUCCESS)
-    {
-        gmx_file("Cannot read next frame of TNG file");
-    }
-    srenew(*values, sizeof(real) * *nValuesPerFrame * *nAtoms);
-    convert_array_to_real_array(data,
-                                *values,
-                                getDistanceScaleFactor(input),
-                                *nAtoms,
-                                *nValuesPerFrame,
-                                datatype);
-
-    tng_util_frame_current_compression_get(input, blockId, &codecId, &localPrec);
-
-    /* This must be updated if/when more lossy compression methods are added */
-    if (codecId != TNG_TNG_COMPRESSION)
-    {
-        *prec = -1.0;
-    }
-    else
-    {
-        *prec = localPrec;
-    }
-
-    *bOK = TRUE;
-    return TRUE;
-#else
-    GMX_UNUSED_VALUE(input);
-    GMX_UNUSED_VALUE(blockId);
-    GMX_UNUSED_VALUE(values);
-    GMX_UNUSED_VALUE(frameNumber);
-    GMX_UNUSED_VALUE(frameTime);
-    GMX_UNUSED_VALUE(nValuesPerFrame);
-    GMX_UNUSED_VALUE(nAtoms);
-    GMX_UNUSED_VALUE(prec);
-    GMX_UNUSED_VALUE(name);
-    GMX_UNUSED_VALUE(maxLen);
-    GMX_UNUSED_VALUE(bOK);
-    return FALSE;
-#endif
-}
diff --git a/src/gromacs/fileio/tngio_for_tools.h b/src/gromacs/fileio/tngio_for_tools.h
deleted file mode 100644 (file)
index da0d7a7..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
- * and including many others, as listed in the AUTHORS file in the
- * top-level source directory and at http://www.gromacs.org.
- *
- * GROMACS is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * GROMACS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with GROMACS; if not, see
- * http://www.gnu.org/licenses, or write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
- *
- * If you want to redistribute modifications to GROMACS, please
- * consider that scientific software is very special. Version
- * control is crucial - bugs must be traceable. We will be happy to
- * consider code for inclusion in the official distribution, but
- * derived work must not be called official GROMACS. Details are found
- * in the README & COPYING files - if they are missing, get the
- * official version at http://www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the research papers on the package. Check out http://www.gromacs.org.
- */
-#ifndef GMX_FILEIO_TNGIO_FOR_TOOLS_H
-#define GMX_FILEIO_TNGIO_FOR_TOOLS_H
-
-#include <stdio.h>
-
-#include "tng/tng_io_fwd.h"
-
-#include "gromacs/utility/basedefinitions.h"
-#include "gromacs/utility/real.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-#if 0
-}
-#endif
-
-struct gmx_mtop_t;
-struct t_trxframe;
-
-/*! \brief Prepare to write TNG output from trajectory conversion tools */
-void gmx_prepare_tng_writing(const char              *filename,
-                             char                     mode,
-                             tng_trajectory_t        *in,
-                             tng_trajectory_t        *out,
-                             int                      nAtoms,
-                             const struct gmx_mtop_t *mtop,
-                             const int               *index,
-                             const char              *indexGroupName);
-
-/*! \brief Write a trxframe to a TNG file
- *
- * \param output Trajectory to write to
- * \param frame  Frame data to write
- * \param natoms Number of atoms to actually write
- *
- * The natoms field in frame is the number of atoms in the system. The
- * parameter natoms supports writing an index-group subset of the
- * atoms.
- */
-void gmx_write_tng_from_trxframe(tng_trajectory_t        output,
-                                 const t_trxframe       *frame,
-                                 int                     natoms);
-
-/*! \brief Creates a molecule containing only the indexed atoms and sets
- * the number of all other molecules to 0. Works similar to a
- * selection group. */
-void gmx_tng_setup_atom_subgroup(tng_trajectory_t tng,
-                                 const int        nind,
-                                 const int       *ind,
-                                 const char      *name);
-
-/*! \brief Read the first/next TNG frame. */
-gmx_bool gmx_read_next_tng_frame(tng_trajectory_t            input,
-                                 struct t_trxframe          *fr,
-                                 gmx_int64_t                *requestedIds,
-                                 int                         numRequestedIds);
-
-/*! \brief Print the molecule system to stream */
-void gmx_print_tng_molecule_system(tng_trajectory_t input,
-                                   FILE            *stream);
-
-/*! \brief Get a list of block IDs present in the next frame with data. */
-gmx_bool gmx_get_tng_data_block_types_of_next_frame(tng_trajectory_t     input,
-                                                    int                  frame,
-                                                    int                  nRequestedIds,
-                                                    gmx_int64_t         *requestedIds,
-                                                    gmx_int64_t         *nextFrame,
-                                                    gmx_int64_t         *nBlocks,
-                                                    gmx_int64_t        **blockIds);
-
-/*! \brief Get data of the next frame with data from the data block
- * with the specified block ID. */
-gmx_bool gmx_get_tng_data_next_frame_of_block_type(tng_trajectory_t     input,
-                                                   gmx_int64_t          blockId,
-                                                   real               **values,
-                                                   gmx_int64_t         *frameNumber,
-                                                   double              *frameTime,
-                                                   gmx_int64_t         *nValuesPerFrame,
-                                                   gmx_int64_t         *nAtoms,
-                                                   real                *prec,
-                                                   char                *name,
-                                                   int                  maxLen,
-                                                   gmx_bool            *bOK);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
index 4b67fc762aa96042d9c256065612b6fd6215433c..c85e1530ddc545f716ae94e92ea1e2c3eeb9a58e 100644 (file)
@@ -68,6 +68,7 @@
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/futil.h"
+#include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/snprintf.h"
 #include "gromacs/utility/txtdump.h"
@@ -146,7 +147,7 @@ static const int tpx_generation = 26;
 /* This number should be the most recent backwards incompatible version
  * I.e., if this number is 9, we cannot read tpx version 9 with this code.
  */
-static const int tpx_incompatible_version = 9;
+static const int tpx_incompatible_version = 30; // GMX3.2 has version 31
 
 
 
@@ -162,24 +163,16 @@ typedef struct {
  * 2. ascending file version number
  */
 static const t_ftupd ftupd[] = {
-    { 20, F_CUBICBONDS        },
-    { 20, F_CONNBONDS         },
-    { 20, F_HARMONIC          },
     { 34, F_FENEBONDS         },
     { 43, F_TABBONDS          },
     { 43, F_TABBONDSNC        },
     { 70, F_RESTRBONDS        },
     { tpxv_RestrictedBendingAndCombinedAngleTorsionPotentials, F_RESTRANGLES },
     { 76, F_LINEAR_ANGLES     },
-    { 30, F_CROSS_BOND_BONDS  },
-    { 30, F_CROSS_BOND_ANGLES },
-    { 30, F_UREY_BRADLEY      },
     { 34, F_QUARTIC_ANGLES    },
     { 43, F_TABANGLES         },
     { tpxv_RestrictedBendingAndCombinedAngleTorsionPotentials, F_RESTRDIHS },
     { tpxv_RestrictedBendingAndCombinedAngleTorsionPotentials, F_CBTDIHS },
-    { 26, F_FOURDIHS          },
-    { 26, F_PIDIHS            },
     { 43, F_TABDIHS           },
     { 65, F_CMAP              },
     { 60, F_GB12              },
@@ -194,18 +187,11 @@ static const t_ftupd ftupd[] = {
     { 32, F_COUL_RECIP        },
     { 93, F_LJ_RECIP          },
     { 46, F_DPD               },
-    { 30, F_POLARIZATION      },
     { 36, F_THOLE_POL         },
     { 90, F_FBPOSRES          },
-    { 22, F_DISRESVIOL        },
-    { 22, F_ORIRES            },
-    { 22, F_ORIRESDEV         },
-    { 26, F_DIHRES            },
-    { 26, F_DIHRESVIOL        },
     { 49, F_VSITE4FDN         },
     { 50, F_VSITEN            },
     { 46, F_COM_PULL          },
-    { 20, F_EQM               },
     { 46, F_ECONSERVED        },
     { 69, F_VTEMP_NOLONGERUSED},
     { 66, F_PDISPCORR         },
@@ -558,14 +544,7 @@ static void do_fepvals(t_fileio *fio, t_lambda *fepvals, gmx_bool bRead, int fil
             fepvals->separate_dvdl[efptFEP] = TRUE;
         }
     }
-    if (file_version >= 13)
-    {
-        gmx_fio_do_real(fio, fepvals->sc_alpha);
-    }
-    else
-    {
-        fepvals->sc_alpha = 0;
-    }
+    gmx_fio_do_real(fio, fepvals->sc_alpha);
     if (file_version >= 38)
     {
         gmx_fio_do_int(fio, fepvals->sc_power);
@@ -582,14 +561,7 @@ static void do_fepvals(t_fileio *fio, t_lambda *fepvals, gmx_bool bRead, int fil
     {
         fepvals->sc_r_power = 6.0;
     }
-    if (file_version >= 15)
-    {
-        gmx_fio_do_real(fio, fepvals->sc_sigma);
-    }
-    else
-    {
-        fepvals->sc_sigma = 0.3;
-    }
+    gmx_fio_do_real(fio, fepvals->sc_sigma);
     if (bRead)
     {
         if (file_version >= 71)
@@ -951,11 +923,9 @@ static void do_swapcoords_tpx(t_fileio *fio, t_swapcoords *swap, gmx_bool bRead,
 static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
                         int file_version, real *fudgeQQ)
 {
-    int      i, j, k, *tmp, idum = 0;
+    int      i, j, k, idum = 0;
     real     rdum, bd_temp;
-    rvec     vdum;
-    gmx_bool bSimAnn, bdum = 0;
-    real     zerotemptime, finish_t, init_temp, finish_temp;
+    gmx_bool bdum = 0;
 
     if (file_version != tpx_version)
     {
@@ -964,11 +934,6 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
                 file_version, tpx_version);
     }
 
-    if (bRead)
-    {
-        init_inputrec(ir);
-    }
-
     if (file_version == 0)
     {
         return;
@@ -986,21 +951,14 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
         ir->nsteps = idum;
     }
 
-    if (file_version > 25)
+    if (file_version >= 62)
     {
-        if (file_version >= 62)
-        {
-            gmx_fio_do_int64(fio, ir->init_step);
-        }
-        else
-        {
-            gmx_fio_do_int(fio, idum);
-            ir->init_step = idum;
-        }
+        gmx_fio_do_int64(fio, ir->init_step);
     }
     else
     {
-        ir->init_step = 0;
+        gmx_fio_do_int(fio, idum);
+        ir->init_step = idum;
     }
 
     if (file_version >= 58)
@@ -1026,10 +984,6 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
          * since we always want it, also without reading the inputrec.
          */
         gmx_fio_do_int(fio, ir->ePBC);
-        if ((file_version <= 15) && (ir->ePBC == 2))
-        {
-            ir->ePBC = epbcNONE;
-        }
         if (file_version >= 45)
         {
             gmx_fio_do_int(fio, ir->bPeriodicMols);
@@ -1091,21 +1045,14 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
     ir->nstcomm = abs(ir->nstcomm);
 
     /* ignore nstcheckpoint */
-    if (file_version > 25 && file_version < tpxv_RemoveObsoleteParameters1)
+    if (file_version < tpxv_RemoveObsoleteParameters1)
     {
         gmx_fio_do_int(fio, idum);
     }
 
     gmx_fio_do_int(fio, ir->nstcgsteep);
 
-    if (file_version >= 30)
-    {
-        gmx_fio_do_int(fio, ir->nbfgscorr);
-    }
-    else if (bRead)
-    {
-        ir->nbfgscorr = 10;
-    }
+    gmx_fio_do_int(fio, ir->nbfgscorr);
 
     gmx_fio_do_int(fio, ir->nstlog);
     gmx_fio_do_int(fio, ir->nstxout);
@@ -1126,15 +1073,6 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
         ir->delta_t = rdum;
     }
     gmx_fio_do_real(fio, ir->x_compression_precision);
-    if (file_version < 19)
-    {
-        gmx_fio_do_int(fio, idum);
-        gmx_fio_do_int(fio, idum);
-    }
-    if (file_version < 18)
-    {
-        gmx_fio_do_int(fio, idum);
-    }
     if (file_version >= 81)
     {
         gmx_fio_do_real(fio, ir->verletbuf_tol);
@@ -1226,31 +1164,13 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
             ir->epsilon_rf = 1.0;
         }
     }
-    if (file_version >= 29)
-    {
-        gmx_fio_do_real(fio, ir->tabext);
-    }
-    else
-    {
-        ir->tabext = 1.0;
-    }
+    gmx_fio_do_real(fio, ir->tabext);
 
-    if (file_version > 25)
-    {
-        gmx_fio_do_int(fio, ir->gb_algorithm);
-        gmx_fio_do_int(fio, ir->nstgbradii);
-        gmx_fio_do_real(fio, ir->rgbradii);
-        gmx_fio_do_real(fio, ir->gb_saltconc);
-        gmx_fio_do_int(fio, ir->implicit_solvent);
-    }
-    else
-    {
-        ir->gb_algorithm     = egbSTILL;
-        ir->nstgbradii       = 1;
-        ir->rgbradii         = 1.0;
-        ir->gb_saltconc      = 0;
-        ir->implicit_solvent = eisNO;
-    }
+    gmx_fio_do_int(fio, ir->gb_algorithm);
+    gmx_fio_do_int(fio, ir->nstgbradii);
+    gmx_fio_do_real(fio, ir->rgbradii);
+    gmx_fio_do_real(fio, ir->gb_saltconc);
+    gmx_fio_do_int(fio, ir->implicit_solvent);
     if (file_version >= 55)
     {
         gmx_fio_do_real(fio, ir->gb_epsilon_solvent);
@@ -1316,28 +1236,8 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
     {
         ir->ewald_rtol_lj = ir->ewald_rtol;
     }
-
-    if (file_version >= 24)
-    {
-        gmx_fio_do_int(fio, ir->ewald_geometry);
-    }
-    else
-    {
-        ir->ewald_geometry = eewg3D;
-    }
-
-    if (file_version <= 17)
-    {
-        ir->epsilon_surface = 0;
-        if (file_version == 17)
-        {
-            gmx_fio_do_int(fio, idum);
-        }
-    }
-    else
-    {
-        gmx_fio_do_real(fio, ir->epsilon_surface);
-    }
+    gmx_fio_do_int(fio, ir->ewald_geometry);
+    gmx_fio_do_real(fio, ir->epsilon_surface);
 
     /* ignore bOptFFT */
     if (file_version < tpxv_RemoveObsoleteParameters1)
@@ -1367,38 +1267,8 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
     {
         ir->nsttcouple = ir->nstcalcenergy;
     }
-    if (file_version <= 15)
-    {
-        gmx_fio_do_int(fio, idum);
-    }
-    if (file_version <= 17)
-    {
-        gmx_fio_do_int(fio, ir->epct);
-        if (file_version <= 15)
-        {
-            if (ir->epct == 5)
-            {
-                ir->epct = epctSURFACETENSION;
-            }
-            gmx_fio_do_int(fio, idum);
-        }
-        ir->epct -= 1;
-        /* we have removed the NO alternative at the beginning */
-        if (ir->epct == -1)
-        {
-            ir->epc  = epcNO;
-            ir->epct = epctISOTROPIC;
-        }
-        else
-        {
-            ir->epc = epcBERENDSEN;
-        }
-    }
-    else
-    {
-        gmx_fio_do_int(fio, ir->epc);
-        gmx_fio_do_int(fio, ir->epct);
-    }
+    gmx_fio_do_int(fio, ir->epc);
+    gmx_fio_do_int(fio, ir->epct);
     if (file_version >= 71)
     {
         gmx_fio_do_int(fio, ir->nstpcouple);
@@ -1408,36 +1278,12 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
         ir->nstpcouple = ir->nstcalcenergy;
     }
     gmx_fio_do_real(fio, ir->tau_p);
-    if (file_version <= 15)
-    {
-        gmx_fio_do_rvec(fio, vdum);
-        clear_mat(ir->ref_p);
-        for (i = 0; i < DIM; i++)
-        {
-            ir->ref_p[i][i] = vdum[i];
-        }
-    }
-    else
-    {
-        gmx_fio_do_rvec(fio, ir->ref_p[XX]);
-        gmx_fio_do_rvec(fio, ir->ref_p[YY]);
-        gmx_fio_do_rvec(fio, ir->ref_p[ZZ]);
-    }
-    if (file_version <= 15)
-    {
-        gmx_fio_do_rvec(fio, vdum);
-        clear_mat(ir->compress);
-        for (i = 0; i < DIM; i++)
-        {
-            ir->compress[i][i] = vdum[i];
-        }
-    }
-    else
-    {
-        gmx_fio_do_rvec(fio, ir->compress[XX]);
-        gmx_fio_do_rvec(fio, ir->compress[YY]);
-        gmx_fio_do_rvec(fio, ir->compress[ZZ]);
-    }
+    gmx_fio_do_rvec(fio, ir->ref_p[XX]);
+    gmx_fio_do_rvec(fio, ir->ref_p[YY]);
+    gmx_fio_do_rvec(fio, ir->ref_p[ZZ]);
+    gmx_fio_do_rvec(fio, ir->compress[XX]);
+    gmx_fio_do_rvec(fio, ir->compress[YY]);
+    gmx_fio_do_rvec(fio, ir->compress[ZZ]);
     if (file_version >= 47)
     {
         gmx_fio_do_int(fio, ir->refcoord_scaling);
@@ -1450,7 +1296,7 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
         clear_rvec(ir->posres_com);
         clear_rvec(ir->posres_comB);
     }
-    if ((file_version > 25) && (file_version < 79))
+    if (file_version < 79)
     {
         gmx_fio_do_int(fio, ir->andersen_seed);
     }
@@ -1458,11 +1304,6 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
     {
         ir->andersen_seed = 0;
     }
-    if (file_version < 26)
-    {
-        gmx_fio_do_gmx_bool(fio, bSimAnn);
-        gmx_fio_do_real(fio, zerotemptime);
-    }
 
     if (file_version < 37)
     {
@@ -1472,14 +1313,11 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
     gmx_fio_do_real(fio, ir->shake_tol);
     if (file_version < 54)
     {
+        // cppcheck-suppress redundantPointerOp
         gmx_fio_do_real(fio, *fudgeQQ);
     }
 
     gmx_fio_do_int(fio, ir->efep);
-    if (file_version <= 14 && ir->efep != efepNO)
-    {
-        ir->efep = efepYES;
-    }
     do_fepvals(fio, ir->fepvals, bRead, file_version);
 
     if (file_version >= 79)
@@ -1520,36 +1358,16 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
         gmx_fio_do_int(fio, ir->eDisre);
     }
     gmx_fio_do_int(fio, ir->eDisreWeighting);
-    if (file_version < 22)
-    {
-        if (ir->eDisreWeighting == 0)
-        {
-            ir->eDisreWeighting = edrwEqual;
-        }
-        else
-        {
-            ir->eDisreWeighting = edrwConservative;
-        }
-    }
     gmx_fio_do_gmx_bool(fio, ir->bDisreMixed);
     gmx_fio_do_real(fio, ir->dr_fc);
     gmx_fio_do_real(fio, ir->dr_tau);
     gmx_fio_do_int(fio, ir->nstdisreout);
-    if (file_version >= 22)
-    {
-        gmx_fio_do_real(fio, ir->orires_fc);
-        gmx_fio_do_real(fio, ir->orires_tau);
-        gmx_fio_do_int(fio, ir->nstorireout);
-    }
-    else
-    {
-        ir->orires_fc   = 0;
-        ir->orires_tau  = 0;
-        ir->nstorireout = 0;
-    }
+    gmx_fio_do_real(fio, ir->orires_fc);
+    gmx_fio_do_real(fio, ir->orires_tau);
+    gmx_fio_do_int(fio, ir->nstorireout);
 
     /* ignore dihre_fc */
-    if (file_version >= 26 && file_version < 79)
+    if (file_version < 79)
     {
         gmx_fio_do_real(fio, rdum);
         if (file_version < 56)
@@ -1561,49 +1379,13 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
 
     gmx_fio_do_real(fio, ir->em_stepsize);
     gmx_fio_do_real(fio, ir->em_tol);
-    if (file_version >= 22)
-    {
-        gmx_fio_do_gmx_bool(fio, ir->bShakeSOR);
-    }
-    else if (bRead)
-    {
-        ir->bShakeSOR = TRUE;
-    }
-    if (file_version >= 11)
-    {
-        gmx_fio_do_int(fio, ir->niter);
-    }
-    else if (bRead)
-    {
-        ir->niter = 25;
-        fprintf(stderr, "Note: niter not in run input file, setting it to %d\n",
-                ir->niter);
-    }
-    if (file_version >= 21)
-    {
-        gmx_fio_do_real(fio, ir->fc_stepsize);
-    }
-    else
-    {
-        ir->fc_stepsize = 0;
-    }
+    gmx_fio_do_gmx_bool(fio, ir->bShakeSOR);
+    gmx_fio_do_int(fio, ir->niter);
+    gmx_fio_do_real(fio, ir->fc_stepsize);
     gmx_fio_do_int(fio, ir->eConstrAlg);
     gmx_fio_do_int(fio, ir->nProjOrder);
     gmx_fio_do_real(fio, ir->LincsWarnAngle);
-    if (file_version <= 14)
-    {
-        gmx_fio_do_int(fio, idum);
-    }
-    if (file_version >= 26)
-    {
-        gmx_fio_do_int(fio, ir->nLincsIter);
-    }
-    else if (bRead)
-    {
-        ir->nLincsIter = 1;
-        fprintf(stderr, "Note: nLincsIter not in run input file, setting it to %d\n",
-                ir->nLincsIter);
-    }
+    gmx_fio_do_int(fio, ir->nLincsIter);
     if (file_version < 33)
     {
         gmx_fio_do_real(fio, bd_temp);
@@ -1632,14 +1414,8 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
             clear_rvec(ir->deform[i]);
         }
     }
-    if (file_version >= 14)
-    {
-        gmx_fio_do_real(fio, ir->cos_accel);
-    }
-    else if (bRead)
-    {
-        ir->cos_accel = 0;
-    }
+    gmx_fio_do_real(fio, ir->cos_accel);
+
     gmx_fio_do_int(fio, ir->userint1);
     gmx_fio_do_int(fio, ir->userint2);
     gmx_fio_do_int(fio, ir->userint3);
@@ -1784,20 +1560,7 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
     }
     if (ir->opts.ngtc > 0)
     {
-        if (bRead && file_version < 13)
-        {
-            snew(tmp, ir->opts.ngtc);
-            gmx_fio_ndo_int(fio, tmp, ir->opts.ngtc);
-            for (i = 0; i < ir->opts.ngtc; i++)
-            {
-                ir->opts.nrdf[i] = tmp[i];
-            }
-            sfree(tmp);
-        }
-        else
-        {
-            gmx_fio_ndo_real(fio, ir->opts.nrdf, ir->opts.ngtc);
-        }
+        gmx_fio_ndo_real(fio, ir->opts.nrdf, ir->opts.ngtc);
         gmx_fio_ndo_real(fio, ir->opts.ref_t, ir->opts.ngtc);
         gmx_fio_ndo_real(fio, ir->opts.tau_t, ir->opts.ngtc);
         if (file_version < 33 && ir->eI == eiBD)
@@ -1816,55 +1579,22 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
     {
         gmx_fio_ndo_rvec(fio, ir->opts.acc, ir->opts.ngacc);
     }
-    if (file_version >= 12)
-    {
-        gmx_fio_ndo_int(fio, ir->opts.egp_flags,
-                        ir->opts.ngener*ir->opts.ngener);
-    }
+    gmx_fio_ndo_int(fio, ir->opts.egp_flags,
+                    ir->opts.ngener*ir->opts.ngener);
 
-    if (bRead && file_version < 26)
+    /* First read the lists with annealing and npoints for each group */
+    gmx_fio_ndo_int(fio, ir->opts.annealing, ir->opts.ngtc);
+    gmx_fio_ndo_int(fio, ir->opts.anneal_npoints, ir->opts.ngtc);
+    for (j = 0; j < (ir->opts.ngtc); j++)
     {
-        for (i = 0; i < ir->opts.ngtc; i++)
-        {
-            if (bSimAnn)
-            {
-                ir->opts.annealing[i]      = eannSINGLE;
-                ir->opts.anneal_npoints[i] = 2;
-                snew(ir->opts.anneal_time[i], 2);
-                snew(ir->opts.anneal_temp[i], 2);
-                /* calculate the starting/ending temperatures from reft, zerotemptime, and nsteps */
-                finish_t                   = ir->init_t + ir->nsteps * ir->delta_t;
-                init_temp                  = ir->opts.ref_t[i]*(1-ir->init_t/zerotemptime);
-                finish_temp                = ir->opts.ref_t[i]*(1-finish_t/zerotemptime);
-                ir->opts.anneal_time[i][0] = ir->init_t;
-                ir->opts.anneal_time[i][1] = finish_t;
-                ir->opts.anneal_temp[i][0] = init_temp;
-                ir->opts.anneal_temp[i][1] = finish_temp;
-            }
-            else
-            {
-                ir->opts.annealing[i]      = eannNO;
-                ir->opts.anneal_npoints[i] = 0;
-            }
-        }
-    }
-    else
-    {
-        /* file version 26 or later */
-        /* First read the lists with annealing and npoints for each group */
-        gmx_fio_ndo_int(fio, ir->opts.annealing, ir->opts.ngtc);
-        gmx_fio_ndo_int(fio, ir->opts.anneal_npoints, ir->opts.ngtc);
-        for (j = 0; j < (ir->opts.ngtc); j++)
+        k = ir->opts.anneal_npoints[j];
+        if (bRead)
         {
-            k = ir->opts.anneal_npoints[j];
-            if (bRead)
-            {
-                snew(ir->opts.anneal_time[j], k);
-                snew(ir->opts.anneal_temp[j], k);
-            }
-            gmx_fio_ndo_real(fio, ir->opts.anneal_time[j], k);
-            gmx_fio_ndo_real(fio, ir->opts.anneal_temp[j], k);
+            snew(ir->opts.anneal_time[j], k);
+            snew(ir->opts.anneal_temp[j], k);
         }
+        gmx_fio_ndo_real(fio, ir->opts.anneal_time[j], k);
+        gmx_fio_ndo_real(fio, ir->opts.anneal_temp[j], k);
     }
     /* Walls */
     if (file_version >= 45)
@@ -1896,22 +1626,7 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
         ir->wall_ewald_zfac  = 3;
     }
     /* Cosine stuff for electric fields */
-    for (j = 0; (j < DIM); j++)
-    {
-        gmx_fio_do_int(fio, ir->ex[j].n);
-        gmx_fio_do_int(fio, ir->et[j].n);
-        if (bRead)
-        {
-            snew(ir->ex[j].a,  ir->ex[j].n);
-            snew(ir->ex[j].phi, ir->ex[j].n);
-            snew(ir->et[j].a,  ir->et[j].n);
-            snew(ir->et[j].phi, ir->et[j].n);
-        }
-        gmx_fio_ndo_real(fio, ir->ex[j].a,  ir->ex[j].n);
-        gmx_fio_ndo_real(fio, ir->ex[j].phi, ir->ex[j].n);
-        gmx_fio_ndo_real(fio, ir->et[j].a,  ir->et[j].n);
-        gmx_fio_ndo_real(fio, ir->et[j].phi, ir->et[j].n);
-    }
+    ir->efield->doTpxIO(fio, bRead);
 
     /* Swap ions */
     if (file_version >= tpxv_ComputationalElectrophysiology)
@@ -2105,10 +1820,6 @@ void do_iparams(t_fileio *fio, t_functype ftype, t_iparams *iparams,
             gmx_fio_do_real(fio, iparams->anharm_polarize.khyp);
             break;
         case F_WATER_POL:
-            if (file_version < 31)
-            {
-                gmx_fatal(FARGS, "Old tpr files with water_polarization not supported. Make a new.");
-            }
             gmx_fio_do_real(fio, iparams->wpol.al_x);
             gmx_fio_do_real(fio, iparams->wpol.al_y);
             gmx_fio_do_real(fio, iparams->wpol.al_z);
@@ -2211,16 +1922,8 @@ void do_iparams(t_fileio *fio, t_functype ftype, t_iparams *iparams,
         case F_POSRES:
             gmx_fio_do_rvec(fio, iparams->posres.pos0A);
             gmx_fio_do_rvec(fio, iparams->posres.fcA);
-            if (bRead && file_version < 27)
-            {
-                copy_rvec(iparams->posres.pos0A, iparams->posres.pos0B);
-                copy_rvec(iparams->posres.fcA, iparams->posres.fcB);
-            }
-            else
-            {
-                gmx_fio_do_rvec(fio, iparams->posres.pos0B);
-                gmx_fio_do_rvec(fio, iparams->posres.fcB);
-            }
+            gmx_fio_do_rvec(fio, iparams->posres.pos0B);
+            gmx_fio_do_rvec(fio, iparams->posres.fcB);
             break;
         case F_FBPOSRES:
             gmx_fio_do_int(fio, iparams->fbposres.geom);
@@ -2233,10 +1936,7 @@ void do_iparams(t_fileio *fio, t_functype ftype, t_iparams *iparams,
             break;
         case F_RBDIHS:
             gmx_fio_ndo_real(fio, iparams->rbdihs.rbcA, NR_RBDIHS);
-            if (file_version >= 25)
-            {
-                gmx_fio_ndo_real(fio, iparams->rbdihs.rbcB, NR_RBDIHS);
-            }
+            gmx_fio_ndo_real(fio, iparams->rbdihs.rbcB, NR_RBDIHS);
             break;
         case F_FOURDIHS:
             /* Fourier dihedrals are internally represented
@@ -2575,11 +2275,7 @@ static void do_atom(t_fileio *fio, t_atom *atom, int ngrp, gmx_bool bRead,
     {
         atom->atomnumber = 0;
     }
-    if (file_version < 23)
-    {
-        myngrp = 8;
-    }
-    else if (file_version < 39)
+    if (file_version < 39)
     {
         myngrp = 9;
     }
@@ -2609,11 +2305,7 @@ static void do_grps(t_fileio *fio, int ngrp, t_grps grps[], gmx_bool bRead,
 {
     int      j, myngrp;
 
-    if (file_version < 23)
-    {
-        myngrp = 8;
-    }
-    else if (file_version < 39)
+    if (file_version < 39)
     {
         myngrp = 9;
     }
@@ -2708,6 +2400,16 @@ static void do_atoms(t_fileio *fio, t_atoms *atoms, gmx_bool bRead, t_symtab *sy
     }
     if (bRead)
     {
+        /* Since we have always written all t_atom properties in the tpr file
+         * (at least for all backward compatible versions), we don't store
+         * but simple set the booleans here.
+         */
+        atoms->haveMass    = TRUE;
+        atoms->haveCharge  = TRUE;
+        atoms->haveType    = TRUE;
+        atoms->haveBState  = TRUE;
+        atoms->havePdbInfo = FALSE;
+
         snew(atoms->atom, atoms->nr);
         snew(atoms->atomname, atoms->nr);
         snew(atoms->atomtype, atoms->nr);
@@ -2719,24 +2421,18 @@ static void do_atoms(t_fileio *fio, t_atoms *atoms, gmx_bool bRead, t_symtab *sy
         }
         atoms->pdbinfo = NULL;
     }
+    else
+    {
+        GMX_RELEASE_ASSERT(atoms->haveMass && atoms->haveCharge && atoms->haveType && atoms->haveBState, "Mass, charge, atomtype and B-state parameters should be present in t_atoms when writing a tpr file");
+    }
     for (i = 0; (i < atoms->nr); i++)
     {
         do_atom(fio, &atoms->atom[i], egcNR, bRead, file_version, groups, i);
     }
     do_strstr(fio, atoms->nr, atoms->atomname, bRead, symtab);
-    if (bRead && (file_version <= 20))
-    {
-        for (i = 0; i < atoms->nr; i++)
-        {
-            atoms->atomtype[i]  = put_symtab(symtab, "?");
-            atoms->atomtypeB[i] = put_symtab(symtab, "?");
-        }
-    }
-    else
-    {
-        do_strstr(fio, atoms->nr, atoms->atomtype, bRead, symtab);
-        do_strstr(fio, atoms->nr, atoms->atomtypeB, bRead, symtab);
-    }
+    do_strstr(fio, atoms->nr, atoms->atomtype, bRead, symtab);
+    do_strstr(fio, atoms->nr, atoms->atomtypeB, bRead, symtab);
+
     do_resinfo(fio, atoms->nres, atoms->resinfo, bRead, symtab, file_version);
 
     if (file_version < 57)
@@ -2786,44 +2482,28 @@ static void do_atomtypes(t_fileio *fio, t_atomtypes *atomtypes, gmx_bool bRead,
 {
     int      j;
 
-    if (file_version > 25)
+    gmx_fio_do_int(fio, atomtypes->nr);
+    j = atomtypes->nr;
+    if (bRead)
     {
-        gmx_fio_do_int(fio, atomtypes->nr);
-        j = atomtypes->nr;
-        if (bRead)
-        {
-            snew(atomtypes->radius, j);
-            snew(atomtypes->vol, j);
-            snew(atomtypes->surftens, j);
-            snew(atomtypes->atomnumber, j);
-            snew(atomtypes->gb_radius, j);
-            snew(atomtypes->S_hct, j);
-        }
-        gmx_fio_ndo_real(fio, atomtypes->radius, j);
-        gmx_fio_ndo_real(fio, atomtypes->vol, j);
-        gmx_fio_ndo_real(fio, atomtypes->surftens, j);
-        if (file_version >= 40)
-        {
-            gmx_fio_ndo_int(fio, atomtypes->atomnumber, j);
-        }
-        if (file_version >= 60)
-        {
-            gmx_fio_ndo_real(fio, atomtypes->gb_radius, j);
-            gmx_fio_ndo_real(fio, atomtypes->S_hct, j);
-        }
+        snew(atomtypes->radius, j);
+        snew(atomtypes->vol, j);
+        snew(atomtypes->surftens, j);
+        snew(atomtypes->atomnumber, j);
+        snew(atomtypes->gb_radius, j);
+        snew(atomtypes->S_hct, j);
     }
-    else
+    gmx_fio_ndo_real(fio, atomtypes->radius, j);
+    gmx_fio_ndo_real(fio, atomtypes->vol, j);
+    gmx_fio_ndo_real(fio, atomtypes->surftens, j);
+    if (file_version >= 40)
     {
-        /* File versions prior to 26 cannot do GBSA,
-         * so they dont use this structure
-         */
-        atomtypes->nr         = 0;
-        atomtypes->radius     = NULL;
-        atomtypes->vol        = NULL;
-        atomtypes->surftens   = NULL;
-        atomtypes->atomnumber = NULL;
-        atomtypes->gb_radius  = NULL;
-        atomtypes->S_hct      = NULL;
+        gmx_fio_ndo_int(fio, atomtypes->atomnumber, j);
+    }
+    if (file_version >= 60)
+    {
+        gmx_fio_ndo_real(fio, atomtypes->gb_radius, j);
+        gmx_fio_ndo_real(fio, atomtypes->S_hct, j);
     }
 }
 
@@ -3312,14 +2992,7 @@ static void do_tpxheader(t_fileio *fio, gmx_bool bRead, t_tpxheader *tpx,
         gmx_fio_do_string(fio, file_tag);
     }
 
-    if (fileVersion >= 26)
-    {
-        gmx_fio_do_int(fio, fileGeneration);
-    }
-    else
-    {
-        fileGeneration = 0;
-    }
+    gmx_fio_do_int(fio, fileGeneration);
 
     if (fileVersion >= 81)
     {
@@ -3369,14 +3042,8 @@ static void do_tpxheader(t_fileio *fio, gmx_bool bRead, t_tpxheader *tpx,
     }
 
     gmx_fio_do_int(fio, tpx->natoms);
-    if (fileVersion >= 28)
-    {
-        gmx_fio_do_int(fio, tpx->ngtc);
-    }
-    else
-    {
-        tpx->ngtc = 0;
-    }
+    gmx_fio_do_int(fio, tpx->ngtc);
+
     if (fileVersion < 62)
     {
         gmx_fio_do_int(fio, idum);
@@ -3402,30 +3069,34 @@ static void do_tpxheader(t_fileio *fio, gmx_bool bRead, t_tpxheader *tpx,
 }
 
 static int do_tpx(t_fileio *fio, gmx_bool bRead,
-                  t_inputrec *ir, t_state *state, gmx_mtop_t *mtop,
-                  gmx_bool bXVallocated)
+                  t_inputrec *ir, t_state *state, rvec *x, rvec *v,
+                  gmx_mtop_t *mtop)
 {
     t_tpxheader     tpx;
-    t_inputrec      dum_ir;
     gmx_mtop_t      dum_top;
     gmx_bool        TopOnlyOK;
-    rvec           *xptr, *vptr;
     int             ePBC;
     gmx_bool        bPeriodicMols;
 
     if (!bRead)
     {
+        GMX_RELEASE_ASSERT(x == NULL && v == NULL, "Passing separate x and v pointers to do_tpx() is not supported when writing");
+
         tpx.natoms    = state->natoms;
         tpx.ngtc      = state->ngtc;
         tpx.fep_state = state->fep_state;
         tpx.lambda    = state->lambda[efptFEP];
         tpx.bIr       = (ir       != NULL);
         tpx.bTop      = (mtop     != NULL);
-        tpx.bX        = (state->x != NULL);
-        tpx.bV        = (state->v != NULL);
+        tpx.bX        = (state->flags & (1 << estX));
+        tpx.bV        = (state->flags & (1 << estV));
         tpx.bF        = FALSE;
         tpx.bBox      = TRUE;
     }
+    else
+    {
+        GMX_RELEASE_ASSERT(!(x == NULL && v != NULL), "Passing x==NULL and v!=NULL is not supported");
+    }
 
     TopOnlyOK = (ir == NULL);
 
@@ -3436,15 +3107,9 @@ static int do_tpx(t_fileio *fio, gmx_bool bRead,
     if (bRead)
     {
         state->flags  = 0;
-        if (bXVallocated)
+        if (x != NULL)
         {
-            xptr = state->x;
-            vptr = state->v;
             init_state(state, 0, tpx.ngtc, 0, 0, 0);
-            state->natoms = tpx.natoms;
-            state->nalloc = tpx.natoms;
-            state->x      = xptr;
-            state->v      = vptr;
         }
         else
         {
@@ -3452,6 +3117,12 @@ static int do_tpx(t_fileio *fio, gmx_bool bRead,
         }
     }
 
+    if (x == NULL)
+    {
+        x = as_rvec_array(state->x.data());
+        v = as_rvec_array(state->v.data());
+    }
+
 #define do_test(fio, b, p) if (bRead && (p != NULL) && !b) gmx_fatal(FARGS, "No %s in %s",#p, gmx_fio_getname(fio))
 
     do_test(fio, tpx.bBox, state->box);
@@ -3467,18 +3138,15 @@ static int do_tpx(t_fileio *fio, gmx_bool bRead,
             /* We initialize box_rel after reading the inputrec */
             clear_mat(state->box_rel);
         }
-        if (fileVersion >= 28)
+        gmx_fio_ndo_rvec(fio, state->boxv, DIM);
+        if (fileVersion < 56)
         {
-            gmx_fio_ndo_rvec(fio, state->boxv, DIM);
-            if (fileVersion < 56)
-            {
-                matrix mdum;
-                gmx_fio_ndo_rvec(fio, mdum, DIM);
-            }
+            matrix mdum;
+            gmx_fio_ndo_rvec(fio, mdum, DIM);
         }
     }
 
-    if (state->ngtc > 0 && fileVersion >= 28)
+    if (state->ngtc > 0)
     {
         real *dumv;
         snew(dumv, state->ngtc);
@@ -3491,30 +3159,6 @@ static int do_tpx(t_fileio *fio, gmx_bool bRead,
         sfree(dumv);
     }
 
-    /* Prior to tpx version 26, the inputrec was here.
-     * I moved it to enable partial forward-compatibility
-     * for analysis/viewer programs.
-     */
-    if (fileVersion < 26)
-    {
-        do_test(fio, tpx.bIr, ir);
-        if (tpx.bIr)
-        {
-            if (ir)
-            {
-                do_inputrec(fio, ir, bRead, fileVersion,
-                            mtop ? &mtop->ffparams.fudgeQQ : NULL);
-            }
-            else
-            {
-                do_inputrec(fio, &dum_ir, bRead, fileVersion,
-                            mtop ? &mtop->ffparams.fudgeQQ : NULL);
-                done_inputrec(&dum_ir);
-            }
-
-        }
-    }
-
     do_test(fio, tpx.bTop, mtop);
     if (tpx.bTop)
     {
@@ -3525,27 +3169,27 @@ static int do_tpx(t_fileio *fio, gmx_bool bRead,
         else
         {
             do_mtop(fio, &dum_top, bRead, fileVersion);
-            done_mtop(&dum_top, TRUE);
+            done_mtop(&dum_top);
         }
     }
-    do_test(fio, tpx.bX, state->x);
+    do_test(fio, tpx.bX, x);
     if (tpx.bX)
     {
         if (bRead)
         {
             state->flags |= (1<<estX);
         }
-        gmx_fio_ndo_rvec(fio, state->x, state->natoms);
+        gmx_fio_ndo_rvec(fio, x, tpx.natoms);
     }
 
-    do_test(fio, tpx.bV, state->v);
+    do_test(fio, tpx.bV, v);
     if (tpx.bV)
     {
         if (bRead)
         {
             state->flags |= (1<<estV);
         }
-        gmx_fio_ndo_rvec(fio, state->v, state->natoms);
+        gmx_fio_ndo_rvec(fio, v, tpx.natoms);
     }
 
     // No need to run do_test when the last argument is NULL
@@ -3553,7 +3197,7 @@ static int do_tpx(t_fileio *fio, gmx_bool bRead,
     {
         rvec *dummyForces;
         snew(dummyForces, state->natoms);
-        gmx_fio_ndo_rvec(fio, dummyForces, state->natoms);
+        gmx_fio_ndo_rvec(fio, dummyForces, tpx.natoms);
         sfree(dummyForces);
     }
 
@@ -3566,42 +3210,40 @@ static int do_tpx(t_fileio *fio, gmx_bool bRead,
      */
     ePBC          = -1;
     bPeriodicMols = FALSE;
-    if (fileVersion >= 26)
+
+    do_test(fio, tpx.bIr, ir);
+    if (tpx.bIr)
     {
-        do_test(fio, tpx.bIr, ir);
-        if (tpx.bIr)
+        if (fileVersion >= 53)
         {
-            if (fileVersion >= 53)
+            /* Removed the pbc info from do_inputrec, since we always want it */
+            if (!bRead)
             {
-                /* Removed the pbc info from do_inputrec, since we always want it */
-                if (!bRead)
-                {
-                    ePBC          = ir->ePBC;
-                    bPeriodicMols = ir->bPeriodicMols;
-                }
-                gmx_fio_do_int(fio, ePBC);
-                gmx_fio_do_gmx_bool(fio, bPeriodicMols);
+                ePBC          = ir->ePBC;
+                bPeriodicMols = ir->bPeriodicMols;
             }
-            if (fileGeneration <= tpx_generation && ir)
+            gmx_fio_do_int(fio, ePBC);
+            gmx_fio_do_gmx_bool(fio, bPeriodicMols);
+        }
+        if (fileGeneration <= tpx_generation && ir)
+        {
+            do_inputrec(fio, ir, bRead, fileVersion, mtop ? &mtop->ffparams.fudgeQQ : NULL);
+            if (fileVersion < 51)
             {
-                do_inputrec(fio, ir, bRead, fileVersion, mtop ? &mtop->ffparams.fudgeQQ : NULL);
-                if (fileVersion < 51)
-                {
-                    set_box_rel(ir, state);
-                }
-                if (fileVersion < 53)
-                {
-                    ePBC          = ir->ePBC;
-                    bPeriodicMols = ir->bPeriodicMols;
-                }
+                set_box_rel(ir, state);
             }
-            if (bRead && ir && fileVersion >= 53)
+            if (fileVersion < 53)
             {
-                /* We need to do this after do_inputrec, since that initializes ir */
-                ir->ePBC          = ePBC;
-                ir->bPeriodicMols = bPeriodicMols;
+                ePBC          = ir->ePBC;
+                bPeriodicMols = ir->bPeriodicMols;
             }
         }
+        if (bRead && ir && fileVersion >= 53)
+        {
+            /* We need to do this after do_inputrec, since that initializes ir */
+            ir->ePBC          = ePBC;
+            ir->bPeriodicMols = bPeriodicMols;
+        }
     }
 
     if (bRead)
@@ -3672,8 +3314,8 @@ void write_tpx_state(const char *fn,
     fio = open_tpx(fn, "w");
     do_tpx(fio, FALSE,
            const_cast<t_inputrec *>(ir),
-           const_cast<t_state *>(state),
-           const_cast<gmx_mtop_t *>(mtop), FALSE);
+           const_cast<t_state *>(state), NULL, NULL,
+           const_cast<gmx_mtop_t *>(mtop));
     close_tpx(fio);
 }
 
@@ -3683,7 +3325,7 @@ void read_tpx_state(const char *fn,
     t_fileio *fio;
 
     fio = open_tpx(fn, "r");
-    do_tpx(fio, TRUE, ir, state, mtop, FALSE);
+    do_tpx(fio, TRUE, ir, state, NULL, NULL, mtop);
     close_tpx(fio);
 }
 
@@ -3692,22 +3334,17 @@ int read_tpx(const char *fn,
              rvec *x, rvec *v, gmx_mtop_t *mtop)
 {
     t_fileio *fio;
-    t_state   state;
+    t_state   state {};
     int       ePBC;
 
-    state.x = x;
-    state.v = v;
     fio     = open_tpx(fn, "r");
-    ePBC    = do_tpx(fio, TRUE, ir, &state, mtop, TRUE);
+    ePBC    = do_tpx(fio, TRUE, ir, &state, x, v, mtop);
     close_tpx(fio);
-    *natoms = state.natoms;
+    *natoms = mtop->natoms;
     if (box)
     {
         copy_mat(state.box, box);
     }
-    state.x = NULL;
-    state.v = NULL;
-    done_state(&state);
 
     return ePBC;
 }
@@ -3721,7 +3358,7 @@ int read_tpx_top(const char *fn,
 
     ePBC = read_tpx(fn, ir, box, natoms, x, v, &mtop);
 
-    *top = gmx_mtop_t_to_t_topology(&mtop);
+    *top = gmx_mtop_t_to_t_topology(&mtop, true);
 
     return ePBC;
 }
index 94432e65f9fc9e85a7c3fc4d25efded40d4fc565..ec6ee9c04e32585b486284f16061c6aa9de6d8b2 100644 (file)
@@ -55,7 +55,6 @@
 #include "gromacs/fileio/pdbio.h"
 #include "gromacs/fileio/timecontrol.h"
 #include "gromacs/fileio/tngio.h"
-#include "gromacs/fileio/tngio_for_tools.h"
 #include "gromacs/fileio/tpxio.h"
 #include "gromacs/fileio/trrio.h"
 #include "gromacs/fileio/xdrf.h"
@@ -88,7 +87,6 @@ struct t_trxstatus
                                                * for skipping frames with -dt     */
     real                    tf;               /* internal frame time              */
     t_trxframe             *xframe;
-    int                     nxframe;
     t_fileio               *fio;
     tng_trajectory_t        tng;
     int                     natoms;
@@ -170,7 +168,6 @@ static void initcount(t_trxstatus *status)
 static void status_init(t_trxstatus *status)
 {
     status->flags           = 0;
-    status->nxframe         = 0;
     status->xframe          = NULL;
     status->fio             = NULL;
     status->__frame         = -1;
@@ -945,7 +942,6 @@ int read_first_frame(const gmx_output_env_t *oenv, t_trxstatus **status,
     snew((*status), 1);
 
     status_init( *status );
-    (*status)->nxframe = 1;
     initcount(*status);
     (*status)->flags = flags;
 
@@ -1100,7 +1096,6 @@ int read_first_x(const gmx_output_env_t *oenv, t_trxstatus **status, const char
     read_first_frame(oenv, status, fn, &fr, TRX_NEED_X);
 
     snew((*status)->xframe, 1);
-    (*status)->nxframe   = 1;
     (*(*status)->xframe) = fr;
     *t                   = (*status)->xframe->time;
     *x                   = (*status)->xframe->x;
index 6034a4f811eaa2e3f3cc8155647d2f9e9d8a494d..db6e22421dabd15ddd91b2c9cbd6c7252b62dfad 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -38,6 +38,7 @@
 
 #include "xvgr.h"
 
+#include <cassert>
 #include <cctype>
 #include <cstring>
 
@@ -692,6 +693,7 @@ int read_xvg_legend(const char *fn, double ***y, int *ny,
     {
         if (*ny - 1 > legend_nalloc)
         {
+            assert(legend);
             srenew(*legend, *ny-1);
             for (set = legend_nalloc; set < *ny-1; set++)
             {
index 1c9f474d14e6cdd946f38f2d8db0da4f636e1c49..74f1514265e4e39d2769f38868e8a083dcb2ca27 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -133,8 +133,7 @@ int BinarySearch (real *array, int low, int high, real key, int direction)
         }
         return iMin;
     }
-
-    else if (direction < 0)
+    else
     {
         while (iMax-iMin > 1)
         {
@@ -149,9 +148,7 @@ int BinarySearch (real *array, int low, int high, real key, int direction)
             }
         }
         return iMin-1;
-
-    } /*end -ifelse direction*/
-    return -1;
+    }
 }
 
 
@@ -181,7 +178,7 @@ int LinearSearch (double *array, int startindx, int stopindx,
             }
         }
     }
-    else if (direction < 0)
+    else
     {
         for (i = stopindx; i >= startindx; i--)
         {
@@ -194,10 +191,5 @@ int LinearSearch (double *array, int startindx, int stopindx,
         }
     }
 
-    else
-    {
-        gmx_fatal(FARGS, "Startindex=stopindex=%d\n", startindx);
-    }
-
     return -1;
 }
index 3e69165cb76d2e13b63e826b66011ced485ef83d..41e7acb79014b5b135f885e9ec69966e37e2ba63 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -181,7 +181,7 @@ static void delete_from_atoms(t_atoms *atoms, int inr)
         atoms->atom[i] = atoms->atom[i+1];
     }
 
-    if (atoms->pdbinfo)
+    if (atoms->havePdbInfo)
     {
         /* Shift the pdbatom struct down */
         for (i = inr; (i < atoms->nr-1); i++)
index 15fbfb13f403129bd9c1959b6a8406e4009f6c8f..28971476152d63c09af61a42dd258221de48824f 100644 (file)
@@ -36,6 +36,7 @@
  */
 #include "gmxpre.h"
 
+#include <cassert>
 #include <cmath>
 #include <cstdlib>
 #include <cstring>
@@ -180,6 +181,7 @@ static void write_xvgr_graphs(const char *file, int ngraphs, int nsetspergraph,
         }
         else
         {
+            assert(sy);
             ymin = sy[g][0][0];
             ymax = sy[g][0][0];
             for (s = 0; s < nsetspergraph; s++)
index 8ed9dc6acf25e7a2f1f28b0a6ad4451819ddfb43..bf9549a7c9077cd3489610e1d1cb3035e40e4a82 100644 (file)
@@ -1132,6 +1132,7 @@ int gmx_analyze(int argc, char *argv[])
     if (!parse_common_args(&argc, argv, PCA_CAN_VIEW,
                            NFILE, fnm, npargs, ppa, asize(desc), desc, 0, NULL, &oenv))
     {
+        sfree(ppa);
         return 0;
     }
 
index 3bf3634461a902a5c100009302f6129c37381c66..5ebdeb124a4ef1cc736159003faf59bf2d3fc99f 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -191,6 +191,7 @@ int gmx_g_angle(int argc, char *argv[])
                            NFILE, fnm, npargs, ppa, asize(desc), desc, asize(bugs), bugs,
                            &oenv))
     {
+        sfree(ppa);
         return 0;
     }
 
index 131e4142891eccd0d22c924e3306ea0a799cc698..f3412fcb5f6bc291f2d9760127b9aba270d6ff8a 100644 (file)
@@ -1144,6 +1144,8 @@ static void order_params(FILE *log,
     {
         real x0, y0, z0;
 
+        atoms->havePdbInfo = TRUE;
+
         if (NULL == atoms->pdbinfo)
         {
             snew(atoms->pdbinfo, atoms->nr);
@@ -1398,6 +1400,7 @@ int gmx_chi(int argc, char *argv[])
                            NFILE, fnm, npargs, ppa, asize(desc), desc, asize(bugs), bugs,
                            &oenv))
     {
+        sfree(ppa);
         return 0;
     }
 
index 4df864b0a880eb88eb93188469fe7f966370209b..f8a90473237217a3d612ec00d44377a889b5ab10 100644 (file)
@@ -330,43 +330,20 @@ static real rms_dist(int isize, real **d, real **d_r)
     return std::sqrt(r2);
 }
 
-static int rms_dist_comp(const void *a, const void *b)
+static bool rms_dist_comp(const t_dist &a, const t_dist &b)
 {
-    t_dist *da, *db;
-
-    da = (t_dist *)a;
-    db = (t_dist *)b;
-
-    if (da->dist - db->dist < 0)
-    {
-        return -1;
-    }
-    else if (da->dist - db->dist > 0)
-    {
-        return 1;
-    }
-    return 0;
+    return a.dist < b.dist;
 }
 
-static int clust_id_comp(const void *a, const void *b)
+static bool clust_id_comp(const t_clustid &a, const t_clustid &b)
 {
-    t_clustid *da, *db;
-
-    da = (t_clustid *)a;
-    db = (t_clustid *)b;
-
-    return da->clust - db->clust;
+    return a.clust < b.clust;
 }
 
-static int nrnb_comp(const void *a, const void *b)
+static bool nrnb_comp(const t_nnb &a, const t_nnb &b)
 {
-    t_nnb *da, *db;
-
-    da = (t_nnb *)a;
-    db = (t_nnb *)b;
-
-    /* return the b-a, we want highest first */
-    return db->nr - da->nr;
+    /* return b<a, we want highest first */
+    return b.nr < a.nr;
 }
 
 void gather(t_mat *m, real cutoff, t_clusters *clust)
@@ -393,7 +370,7 @@ void gather(t_mat *m, real cutoff, t_clusters *clust)
     {
         gmx_incons("gather algortihm");
     }
-    qsort(d, nn, sizeof(d[0]), rms_dist_comp);
+    std::sort(d, d+nn, rms_dist_comp);
 
     /* Now we make a cluster index for all of the conformations */
     c = new_clustid(n1);
@@ -424,7 +401,7 @@ void gather(t_mat *m, real cutoff, t_clusters *clust)
     while (bChange);
     fprintf(stderr, "\nSorting and renumbering clusters\n");
     /* Sort on cluster number */
-    qsort(c, n1, sizeof(c[0]), clust_id_comp);
+    std::sort(c, c+n1, clust_id_comp);
 
     /* Renumber clusters */
     cid = 1;
@@ -526,7 +503,7 @@ static void jarvis_patrick(int n1, real **mat, int M, int P,
             row[j].j    = j;
             row[j].dist = mat[i][j];
         }
-        qsort(row, n1, sizeof(row[0]), rms_dist_comp);
+        std::sort(row, row+n1, rms_dist_comp);
         if (M > 0)
         {
             /* Put the M nearest neighbors in the list */
@@ -623,7 +600,7 @@ static void jarvis_patrick(int n1, real **mat, int M, int P,
 
     fprintf(stderr, "\nSorting and renumbering clusters\n");
     /* Sort on cluster number */
-    qsort(c, n1, sizeof(c[0]), clust_id_comp);
+    std::sort(c, c+n1, clust_id_comp);
 
     /* Renumber clusters */
     cid = 1;
@@ -720,7 +697,7 @@ static void gromos(int n1, real **mat, real rmsdcut, t_clusters *clust)
     sfree(row);
 
     /* sort neighbor list on number of neighbors, largest first */
-    qsort(nnb, n1, sizeof(nnb[0]), nrnb_comp);
+    std::sort(nnb, nnb+n1, nrnb_comp);
 
     if (debug)
     {
@@ -763,7 +740,7 @@ static void gromos(int n1, real **mat, real rmsdcut, t_clusters *clust)
         }
         /* sort again on nnb[].nr, because we have new # neighbors: */
         /* but we only need to sort upto i, i.e. when nnb[].nr>0 */
-        qsort(nnb, i, sizeof(nnb[0]), nrnb_comp);
+        std::sort(nnb, nnb+i, nrnb_comp);
 
         fprintf(stderr, "\b\b\b\b%4d", k);
         /* new cluster id */
index 0bf6fb501eecf4d0387853e1c7f19528c708dbbe..d432d47cbec96ed42be7702fbd682dfe14ba7d55 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2007, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -52,7 +52,7 @@
 #include "gromacs/math/vec.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/topology/index.h"
-#include "gromacs/topology/mtop_util.h"
+#include "gromacs/topology/mtop_lookup.h"
 #include "gromacs/topology/topology.h"
 #include "gromacs/trajectory/trajectoryframe.h"
 #include "gromacs/utility/arraysize.h"
@@ -85,8 +85,6 @@ static void clust_size(const char *ndx, const char *trx, const char *xpm,
     gmx_mtop_t           *mtop = NULL;
     int                   ePBC = -1;
     t_block              *mols = NULL;
-    gmx_mtop_atomlookup_t alook;
-    t_atom               *atom;
     int                   ii, jj;
     real                  temp, tfac;
     /* Cluster size distribution (matrix) */
@@ -157,8 +155,6 @@ static void clust_size(const char *ndx, const char *trx, const char *xpm,
         rd_index(ndx, 1, &nindex, &index, &gname);
     }
 
-    alook = gmx_mtop_atomlookup_init(mtop);
-
     snew(clust_index, nindex);
     snew(clust_size, nindex);
     cut2   = cut*cut;
@@ -171,6 +167,7 @@ static void clust_size(const char *ndx, const char *trx, const char *xpm,
     }
     max_clust_size = 1;
     max_clust_ind  = -1;
+    int molb       = 0;
     do
     {
         if ((nskip == 0) || ((nskip > 0) && ((nframe % nskip) == 0)))
@@ -323,9 +320,9 @@ static void clust_size(const char *ndx, const char *trx, const char *xpm,
                     {
                         if (clust_index[i] == max_clust_ind)
                         {
-                            ai    = index[i];
-                            gmx_mtop_atomnr_to_atom(alook, ai, &atom);
-                            ekin += 0.5*atom->m*iprod(v[ai], v[ai]);
+                            ai      = index[i];
+                            real            m  = mtopGetAtomMass(mtop, ai, &molb);
+                            ekin   += 0.5*m*iprod(v[ai], v[ai]);
                         }
                     }
                     temp = (ekin*2.0)/(3.0*tfac*max_clust_size*BOLTZ);
@@ -342,8 +339,6 @@ static void clust_size(const char *ndx, const char *trx, const char *xpm,
     xvgrclose(hp);
     xvgrclose(tp);
 
-    gmx_mtop_atomlookup_destroy(alook);
-
     if (max_clust_ind >= 0)
     {
         fp = gmx_ffopen(mcn, "w");
index 7285a059bdcd212450c9b640b180997a46dd2acc..a5ed70c7ea61e0a449ba2945e2bf9d1b2979c959 100644 (file)
@@ -739,6 +739,8 @@ int gmx_confrms(int argc, char *argv[])
                 srenew(atoms1->pdbinfo, atoms1->nr);
                 srenew(atoms1->atom, atoms1->nr); /* Why renew atom? */
 
+                atoms1->havePdbInfo = TRUE;
+
                 /* Avoid segfaults when writing the pdb-file */
                 for (i = 0; i < atoms1->nr; i++)
                 {
index 99be1dab8cfb002ab720ea077d3a6bbbd7586eaa..f6654953db1a064c2c0ad7c15b047c425da187d4 100644 (file)
@@ -1620,6 +1620,7 @@ int gmx_dipoles(int argc, char *argv[])
     if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW,
                            NFILE, fnm, npargs, ppa, asize(desc), desc, 0, NULL, &oenv))
     {
+        sfree(ppa);
         return 0;
     }
 
index 94dc678cda99126a2d2c54e5054c361899d2be17..1248084f35d25c88ff356b6fd871d381dcf5ef7d 100644 (file)
@@ -60,6 +60,7 @@
 #include "gromacs/mdlib/force.h"
 #include "gromacs/mdlib/mdatoms.h"
 #include "gromacs/mdlib/mdrun.h"
+#include "gromacs/mdrunutility/mdmodules.h"
 #include "gromacs/mdtypes/fcdata.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
@@ -690,7 +691,6 @@ int gmx_disre(int argc, char *argv[])
 
     FILE             *out = NULL, *aver = NULL, *numv = NULL, *maxxv = NULL, *xvg = NULL;
     t_tpxheader       header;
-    t_inputrec        ir;
     gmx_mtop_t        mtop;
     rvec             *xtop;
     gmx_localtop_t   *top;
@@ -748,9 +748,12 @@ int gmx_disre(int argc, char *argv[])
         init5(ntop);
     }
 
+    gmx::MDModules  mdModules;
+    t_inputrec     *ir = mdModules.inputrec();
+
     read_tpxheader(ftp2fn(efTPR, NFILE, fnm), &header, FALSE);
     snew(xtop, header.natoms);
-    read_tpx(ftp2fn(efTPR, NFILE, fnm), &ir, box, &ntopatoms, xtop, NULL, &mtop);
+    read_tpx(ftp2fn(efTPR, NFILE, fnm), ir, box, &ntopatoms, xtop, NULL, &mtop);
     bPDB = opt2bSet("-q", NFILE, fnm);
     if (bPDB)
     {
@@ -770,15 +773,16 @@ int gmx_disre(int argc, char *argv[])
         {
             snew(atoms->pdbinfo, atoms->nr);
         }
+        atoms->havePdbInfo = TRUE;
     }
 
-    top = gmx_mtop_generate_local_top(&mtop, ir.efep != efepNO);
+    top = gmx_mtop_generate_local_top(&mtop, ir->efep != efepNO);
 
     g        = NULL;
     pbc_null = NULL;
-    if (ir.ePBC != epbcNONE)
+    if (ir->ePBC != epbcNONE)
     {
-        if (ir.bPeriodicMols)
+        if (ir->bPeriodicMols)
         {
             pbc_null = &pbc;
         }
@@ -810,8 +814,8 @@ int gmx_disre(int argc, char *argv[])
         isize = 0;
     }
 
-    ir.dr_tau = 0.0;
-    init_disres(fplog, &mtop, &ir, NULL, &fcd, NULL, FALSE);
+    ir->dr_tau = 0.0;
+    init_disres(fplog, &mtop, ir, NULL, &fcd, NULL, FALSE);
 
     natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box);
     snew(f, 5*natoms);
@@ -838,23 +842,23 @@ int gmx_disre(int argc, char *argv[])
                          "Largest Violation", "Time (ps)", "nm", oenv);
     }
 
-    mdatoms = init_mdatoms(fplog, &mtop, ir.efep != efepNO);
-    atoms2md(&mtop, &ir, 0, NULL, mtop.natoms, mdatoms);
-    update_mdatoms(mdatoms, ir.fepvals->init_lambda);
+    mdatoms = init_mdatoms(fplog, &mtop, ir->efep != efepNO);
+    atoms2md(&mtop, ir, -1, NULL, mtop.natoms, mdatoms);
+    update_mdatoms(mdatoms, ir->fepvals->init_lambda);
     init_nrnb(&nrnb);
-    if (ir.ePBC != epbcNONE)
+    if (ir->ePBC != epbcNONE)
     {
-        gpbc = gmx_rmpbc_init(&top->idef, ir.ePBC, natoms);
+        gpbc = gmx_rmpbc_init(&top->idef, ir->ePBC, natoms);
     }
 
     j = 0;
     do
     {
-        if (ir.ePBC != epbcNONE)
+        if (ir->ePBC != epbcNONE)
         {
-            if (ir.bPeriodicMols)
+            if (ir->bPeriodicMols)
             {
-                set_pbc(&pbc, ir.ePBC, box);
+                set_pbc(&pbc, ir->ePBC, box);
             }
             else
             {
@@ -915,7 +919,7 @@ int gmx_disre(int argc, char *argv[])
     }
     while (read_next_x(oenv, status, &t, x, box));
     close_trj(status);
-    if (ir.ePBC != epbcNONE)
+    if (ir->ePBC != epbcNONE)
     {
         gmx_rmpbc_done(gpbc);
     }
@@ -935,7 +939,7 @@ int gmx_disre(int argc, char *argv[])
         {
             write_sto_conf(opt2fn("-q", NFILE, fnm),
                            "Coloured by average violation in Angstrom",
-                           atoms, xav, NULL, ir.ePBC, box);
+                           atoms, xav, NULL, ir->ePBC, box);
         }
         dump_disre_matrix(opt2fn_null("-x", NFILE, fnm), &dr, fcd.disres.nres,
                           j, &top->idef, &mtop, max_dr, nlevels, bThird);
index 88a3667a365e329fa6ad3854fef321f92686f3f9..3845ba98ca151538af70ed41abba1208d04ae759 100644 (file)
@@ -328,6 +328,7 @@ int gmx_dos(int argc, char *argv[])
                            NFILE, fnm, npargs, ppa, asize(desc), desc,
                            asize(bugs), bugs, &oenv))
     {
+        sfree(ppa);
         return 0;
     }
 
index 0ac5265afd8089503101562b3b710b97bcbdfe96..362a783db12de13498fa72cfc2d00e12dc179dd6 100644 (file)
@@ -223,7 +223,8 @@ int gmx_dyndom(int argc, char *argv[])
     {
         snew(atoms.pdbinfo, atoms.nr);
     }
-    natoms = atoms.nr;
+    atoms.havePdbInfo = TRUE;
+    natoms            = atoms.nr;
     snew(xout, natoms);
     snew(vout, natoms);
 
index 87fa1bc7004d8142a5f1021c3885c67a9cd6be3f..7973df30fd808937ee605b34089edf779d40f330 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -797,6 +797,8 @@ int gmx_editconf(int argc, char *argv[])
     {
         snew(atoms.pdbinfo, atoms.nr);
     }
+    atoms.havePdbInfo = TRUE;
+
     if (fn2ftp(infile) == efPDB)
     {
         get_pdb_atomnumber(&atoms, aps);
index 97d2be8a7176f0ca13c5bce484f28970689b4f3e..d507bac7ef809b1b84c24186282d3fb7e764d844 100644 (file)
 #include "gromacs/math/units.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdlib/mdebin.h"
+#include "gromacs/mdrunutility/mdmodules.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/topology/ifunc.h"
+#include "gromacs/topology/mtop_lookup.h"
 #include "gromacs/topology/mtop_util.h"
 #include "gromacs/topology/topology.h"
 #include "gromacs/utility/arraysize.h"
@@ -367,20 +369,19 @@ static void get_dhdl_parms(const char *topnm, t_inputrec *ir)
     read_tpx(topnm, ir, box, &natoms, NULL, NULL, &mtop);
 }
 
-static void get_orires_parms(const char *topnm,
+static void get_orires_parms(const char *topnm, t_inputrec *ir,
                              int *nor, int *nex, int **label, real **obs)
 {
     gmx_mtop_t      mtop;
     gmx_localtop_t *top;
-    t_inputrec      ir;
     t_iparams      *ip;
     int             natoms, i;
     t_iatom        *iatom;
     int             nb;
     matrix          box;
 
-    read_tpx(topnm, &ir, box, &natoms, NULL, NULL, &mtop);
-    top = gmx_mtop_generate_local_top(&mtop, ir.efep != efepNO);
+    read_tpx(topnm, ir, box, &natoms, NULL, NULL, &mtop);
+    top = gmx_mtop_generate_local_top(&mtop, ir->efep != efepNO);
 
     ip       = top->idef.iparams;
     iatom    = top->idef.il[F_ORIRES].iatoms;
@@ -1992,7 +1993,6 @@ int gmx_energy(int argc, char *argv[])
     int                timecheck = 0;
     gmx_mtop_t         mtop;
     gmx_localtop_t    *top = NULL;
-    t_inputrec         ir;
     enerdata_t         edat;
     gmx_enxnm_t       *enm = NULL;
     t_enxframe        *frame, *fr = NULL;
@@ -2014,7 +2014,7 @@ int gmx_energy(int argc, char *argv[])
     gmx_bool          *bIsEner = NULL;
     char             **pairleg, **odtleg, **otenleg;
     char             **leg = NULL;
-    char              *anm_j, *anm_k, *resnm_j, *resnm_k;
+    const char        *anm_j, *anm_k, *resnm_j, *resnm_k;
     int                resnr_j, resnr_k;
     const char        *orinst_sub = "@ subtitle \"instantaneous\"\n";
     char               buf[256];
@@ -2052,6 +2052,7 @@ int gmx_energy(int argc, char *argv[])
                            PCA_CAN_VIEW | PCA_CAN_BEGIN | PCA_CAN_END,
                            NFILE, fnm, npargs, ppa, asize(desc), desc, 0, NULL, &oenv))
     {
+        sfree(ppa);
         return 0;
     }
 
@@ -2076,6 +2077,9 @@ int gmx_energy(int argc, char *argv[])
 
     bVisco = opt2bSet("-vis", NFILE, fnm);
 
+    gmx::MDModules  mdModules;
+    t_inputrec     *ir = mdModules.inputrec();
+
     if ((!bDisRe) && (!bDHDL))
     {
         if (bVisco)
@@ -2172,7 +2176,8 @@ int gmx_energy(int argc, char *argv[])
 
         if (bORIRE || bOTEN)
         {
-            get_orires_parms(ftp2fn(efTPR, NFILE, fnm), &nor, &nex, &or_label, &oobs);
+            get_orires_parms(ftp2fn(efTPR, NFILE, fnm), ir,
+                             &nor, &nex, &or_label, &oobs);
         }
 
         if (bORIRE)
@@ -2298,7 +2303,7 @@ int gmx_energy(int argc, char *argv[])
     else if (bDisRe)
     {
         nbounds = get_bounds(ftp2fn(efTPR, NFILE, fnm), &bounds, &index, &pair, &npairs,
-                             &mtop, &top, &ir);
+                             &mtop, &top, ir);
         snew(violaver, npairs);
         out = xvgropen(opt2fn("-o", NFILE, fnm), "Sum of Violations",
                        "Time (ps)", "nm", oenv);
@@ -2310,13 +2315,13 @@ int gmx_energy(int argc, char *argv[])
             if (output_env_get_print_xvgr_codes(oenv))
             {
                 fprintf(fp_pairs, "@ subtitle \"averaged (tau=%g) and instantaneous\"\n",
-                        ir.dr_tau);
+                        ir->dr_tau);
             }
         }
     }
     else if (bDHDL)
     {
-        get_dhdl_parms(ftp2fn(efTPR, NFILE, fnm), &ir);
+        get_dhdl_parms(ftp2fn(efTPR, NFILE, fnm), ir);
     }
 
     /* Initiate energies and set them to zero */
@@ -2472,13 +2477,14 @@ int gmx_energy(int argc, char *argv[])
                               ndisre, top->idef.il[F_DISRES].nr/3);
                 }
                 snew(pairleg, ndisre);
+                int molb = 0;
                 for (i = 0; i < ndisre; i++)
                 {
                     snew(pairleg[i], 30);
                     j = fa[3*i+1];
                     k = fa[3*i+2];
-                    gmx_mtop_atominfo_global(&mtop, j, &anm_j, &resnr_j, &resnm_j);
-                    gmx_mtop_atominfo_global(&mtop, k, &anm_k, &resnr_k, &resnm_k);
+                    mtopGetAtomAndResidueName(&mtop, j, &molb, &anm_j, &resnr_j, &resnm_j, nullptr);
+                    mtopGetAtomAndResidueName(&mtop, k, &molb, &anm_k, &resnr_k, &resnm_k, nullptr);
                     sprintf(pairleg[i], "%d %s %d %s (%d)",
                             resnr_j, anm_j, resnr_k, anm_k,
                             ip[fa[3*i]].disres.label);
@@ -2555,7 +2561,7 @@ int gmx_energy(int argc, char *argv[])
                 }
                 else if (bDHDL)
                 {
-                    do_dhdl(fr, &ir, &fp_dhdl, opt2fn("-odh", NFILE, fnm), bDp, &dh_blocks, &dh_hists, &dh_samples, &dh_lambdas, oenv);
+                    do_dhdl(fr, ir, &fp_dhdl, opt2fn("-odh", NFILE, fnm), bDp, &dh_blocks, &dh_hists, &dh_samples, &dh_lambdas, oenv);
                 }
 
                 /*******************************************
index 23fccd29519f034cfe9cb93ebe7a2d4babb60b0b..0d7248f8a8ec8f8d4d76b759067aa860b14b8621 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -238,6 +238,7 @@ int gmx_gyrate(int argc, char *argv[])
     if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW,
                            NFILE, fnm, npargs, ppa, asize(desc), desc, 0, NULL, &oenv))
     {
+        sfree(ppa);
         return 0;
     }
     bACF = opt2bSet("-acf", NFILE, fnm);
index 2081edd40f3469a74488cc3129e96a0173623725..076ebb4616ef8d2ad987af8311a0c3939cd952d4 100644 (file)
@@ -59,6 +59,7 @@
 #include "gromacs/math/functions.h"
 #include "gromacs/math/units.h"
 #include "gromacs/math/vec.h"
+#include "gromacs/mdrunutility/mdmodules.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/topology/ifunc.h"
@@ -912,8 +913,8 @@ static void reset_nhbonds(t_donors *ddd)
     }
 }
 
-void pbc_correct_gem(rvec dx, matrix box, rvec hbox);
-void pbc_in_gridbox(rvec dx, matrix box);
+static void pbc_correct_gem(rvec dx, matrix box, rvec hbox);
+static void pbc_in_gridbox(rvec dx, matrix box);
 
 static void build_grid(t_hbdata *hb, rvec x[], rvec xshell,
                        gmx_bool bBox, matrix box, rvec hbox,
@@ -1186,7 +1187,7 @@ static void free_grid(ivec ngrid, t_gridcell ****grid)
     g = NULL;
 }
 
-void pbc_correct_gem(rvec dx, matrix box, rvec hbox)
+static void pbc_correct_gem(rvec dx, matrix box, rvec hbox)
 {
     int      m;
     gmx_bool bDone = FALSE;
@@ -1209,7 +1210,7 @@ void pbc_correct_gem(rvec dx, matrix box, rvec hbox)
     }
 }
 
-void pbc_in_gridbox(rvec dx, matrix box)
+static void pbc_in_gridbox(rvec dx, matrix box)
 {
     int      m;
     gmx_bool bDone = FALSE;
@@ -2509,7 +2510,6 @@ int gmx_hbond(int argc, char *argv[])
     t_trxstatus          *status;
     int                   trrStatus = 1;
     t_topology            top;
-    t_inputrec            ir;
     t_pargs              *ppa;
     int                   npargs, natoms, nframes = 0, shatom;
     int                  *isize;
@@ -2549,6 +2549,7 @@ int gmx_hbond(int argc, char *argv[])
     if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_TIME_UNIT, NFILE, fnm, npargs,
                            ppa, asize(desc), desc, asize(bugs), bugs, &oenv))
     {
+        sfree(ppa);
         return 0;
     }
 
@@ -2585,7 +2586,9 @@ int gmx_hbond(int argc, char *argv[])
     hb = mk_hbdata(bHBmap, opt2bSet("-dan", NFILE, fnm), bMerge || bContact);
 
     /* get topology */
-    read_tpx_top(ftp2fn(efTPR, NFILE, fnm), &ir, box, &natoms, NULL, NULL, &top);
+    gmx::MDModules  mdModules;
+    t_inputrec     *ir = mdModules.inputrec();
+    read_tpx_top(ftp2fn(efTPR, NFILE, fnm), ir, box, &natoms, NULL, NULL, &top);
 
     snew(grpnames, grNR);
     snew(index, grNR);
@@ -2763,7 +2766,7 @@ int gmx_hbond(int argc, char *argv[])
                   top.atoms.nr, natoms);
     }
 
-    bBox  = ir.ePBC != epbcNONE;
+    bBox  = (ir->ePBC != epbcNONE);
     grid  = init_grid(bBox, box, (rcut > r2cut) ? rcut : r2cut, ngrid);
     nabin = static_cast<int>(acut/abin);
     nrbin = static_cast<int>(rcut/rbin);
index 56cfa2eb44616fade78a263a7aab5f013dfd5eef..f777dcd1625dc87d792267c2d11fac42330fe8db 100644 (file)
@@ -1012,7 +1012,7 @@ static gmx_bool parse_entry(char **string, int natoms, const t_atoms *atoms,
         if (check_have_atoms(atoms, ostring) &&
             parse_names(string, &n_names, names))
         {
-            if (atoms->atomtype == NULL)
+            if (!(atoms->haveType))
             {
                 printf("Need a run input file to select atom types\n");
             }
index 8947baed5013bd514e59d84bf3c578bb359a730f..078da36b54337d77048d59e966e385457ed46f98 100644 (file)
@@ -298,7 +298,7 @@ static void calc_dist(real rcut, gmx_bool bPBC, int ePBC, matrix box, rvec x[],
                 {
                     nmin_j++;
                 }
-                else if (r2 > rcut2)
+                else
                 {
                     nmax_j++;
                 }
index 0c363ed7c11c0c5c44c79a032e6fe3cd9b991ede..61f3bd68895b2b9182be697d2faebf07526b7c62 100644 (file)
@@ -402,7 +402,7 @@ int gmx_nmeig(int argc, char *argv[])
     }
     std::vector<size_t> atom_index = get_atom_index(&mtop);
 
-    top = gmx_mtop_t_to_t_topology(&mtop);
+    top = gmx_mtop_t_to_t_topology(&mtop, true);
 
     bM       = TRUE;
     int ndim = DIM*atom_index.size();
index 3f8b6ad6a7960ef1e86c350e085838ddf0f79bbf..0b5ef29080927397907fd4c58f9a2b19bb6a65bd 100644 (file)
@@ -51,6 +51,8 @@
 #include "gromacs/math/functions.h"
 #include "gromacs/math/units.h"
 #include "gromacs/math/vec.h"
+#include "gromacs/mdlib/broadcaststructs.h"
+#include "gromacs/mdrunutility/mdmodules.h"
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/utility/pleasecite.h"
 #include "gromacs/utility/smalloc.h"
 
-/* We use the same defines as in broadcaststructs.cpp here */
-#define  block_bc(cr,   d) gmx_bcast(     sizeof(d),     &(d), (cr))
-#define nblock_bc(cr, nr, d) gmx_bcast((nr)*sizeof((d)[0]), (d), (cr))
-#define   snew_bc(cr, d, nr) { if (!MASTER(cr)) {snew((d), (nr)); }}
 /* #define TAKETIME */
 /* #define DEBUG  */
 
@@ -817,7 +815,6 @@ static int prepare_x_q(real *q[], rvec *x[], const gmx_mtop_t *mtop, const rvec
     int                     i;
     int                     nq; /* number of charged particles */
     gmx_mtop_atomloop_all_t aloop;
-    t_atom                 *atom;
 
 
     if (MASTER(cr))
@@ -827,7 +824,7 @@ static int prepare_x_q(real *q[], rvec *x[], const gmx_mtop_t *mtop, const rvec
         nq = 0;
 
         aloop = gmx_mtop_atomloop_all_init(mtop);
-
+        const t_atom *atom;
         while (gmx_mtop_atomloop_all_next(aloop, &i, &atom))
         {
             if (is_charge(atom->q))
@@ -945,7 +942,7 @@ static void estimate_PME_error(t_inputinfo *info, const t_state *state,
     }
 
     /* Prepare an x and q array with only the charged atoms */
-    ncharges = prepare_x_q(&q, &x, mtop, state->x, cr);
+    ncharges = prepare_x_q(&q, &x, mtop, as_rvec_array(state->x.data()), cr);
     if (MASTER(cr))
     {
         calc_q2all(mtop, &(info->q2all), &(info->q2allnr));
@@ -1136,6 +1133,7 @@ int gmx_pme_error(int argc, char *argv[])
                            NFILE, fnm, asize(pa), pa, asize(desc), desc,
                            0, NULL, &oenv))
     {
+        sfree(cr);
         return 0;
     }
 
@@ -1150,10 +1148,11 @@ int gmx_pme_error(int argc, char *argv[])
     create_info(&info);
     info.fourier_sp[0] = fs;
 
+    gmx::MDModules mdModules;
+
     if (MASTER(cr))
     {
-        /* Read in the tpr file */
-        snew(ir, 1);
+        ir = mdModules.inputrec();
         read_tpr_file(opt2fn("-s", NFILE, fnm), &info, &state, &mtop, ir, user_beta, fracself);
         /* Open logfile for reading */
         fp = fopen(opt2fn("-o", NFILE, fnm), "w");
index 0cdbd1a2fc341fc5ac0cf475245285d8be62efb5..3a7f4eaa2aa17928f29ac1cbcb7809be7e3400b6 100644 (file)
@@ -36,6 +36,7 @@
  */
 #include "gmxpre.h"
 
+#include <cassert>
 #include <cmath>
 #include <cstring>
 
@@ -119,6 +120,10 @@ static void average_residues(double f[], double **U, int uind,
     start = 0;
     av    = 0;
     m     = 0;
+    if (!f)
+    {
+        assert(U);
+    }
     for (i = 0; i < isize; i++)
     {
         av += w_rls[index[i]]*(f != NULL ? f[i] : U[i][uind]);
@@ -331,6 +336,7 @@ int gmx_rmsf(int argc, char *argv[])
         refatoms  = &top.atoms;
         pdbx      = xref;
         snew(pdbatoms->pdbinfo, pdbatoms->nr);
+        pdbatoms->havePdbInfo = TRUE;
         copy_mat(box, pdbbox);
     }
 
index f30805be6b568e87421c7318aafdd5643bc5fdbf..a3c14129d27ddad2a6afa6c3a3dac9ee84498084 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -115,6 +115,7 @@ int gmx_rotacf(int argc, char *argv[])
     if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME,
                            NFILE, fnm, npargs, ppa, asize(desc), desc, 0, NULL, &oenv))
     {
+        sfree(ppa);
         return 0;
     }
 
index a1d73058512e55c3c056ce2d97eb8903284c935b..0009d3ecb05923d7c004019b2ac6c31cff46eee7 100644 (file)
@@ -48,6 +48,7 @@
 #include "gromacs/math/functions.h"
 #include "gromacs/math/units.h"
 #include "gromacs/math/vec.h"
+#include "gromacs/mdrunutility/mdmodules.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/pbcutil/rmpbc.h"
@@ -222,7 +223,9 @@ int gmx_spol(int argc, char *argv[])
     }
 
     snew(top, 1);
-    snew(ir, 1);
+    // TODO: Only ePBC is used, not the full inputrec.
+    gmx::MDModules mdModules;
+    ir = mdModules.inputrec();
     read_tpx_top(ftp2fn(efTPR, NFILE, fnm),
                  ir, box, &natoms, NULL, NULL, top);
 
index 0c37c599a8e7deb2a0d1f54dfc6fd87dbfbd344a..5d3dd8bf3258ae2dcd5105007487a72298da409a 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -343,6 +343,7 @@ int gmx_tcaf(int argc, char *argv[])
     if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME,
                            NFILE, fnm, npargs, ppa, asize(desc), desc, 0, NULL, &oenv))
     {
+        sfree(ppa);
         return 0;
     }
 
index 28dbbd9e7981024ec12b1dd5dcad3b56a0b8651c..352ce4fd2b2b0f55a8133ba754cdcd35a99236ad 100644 (file)
@@ -511,6 +511,8 @@ static void write_pdb_bfac(const char *fname, const char *xname,
         {
             snew(atoms->pdbinfo, atoms->nr);
         }
+        atoms->havePdbInfo = TRUE;
+
         if (onedim == -1)
         {
             for (i = 0; i < isize; i++)
@@ -621,7 +623,9 @@ int gmx_traj(int argc, char *argv[])
         "(specified with [TT]-av[tt] or [TT]-af[tt]).[PAR]",
         "Option [TT]-vd[tt] computes a velocity distribution, i.e. the",
         "norm of the vector is plotted. In addition in the same graph",
-        "the kinetic energy distribution is given."
+        "the kinetic energy distribution is given.",
+        "",
+        "See [gmx-trajectory] for plotting similar data for selections."
     };
     static gmx_bool   bMol    = FALSE, bCom = FALSE, bPBC = TRUE, bNoJump = FALSE;
     static gmx_bool   bX      = TRUE, bY = TRUE, bZ = TRUE, bNorm = FALSE, bFP = FALSE;
index 1658d13d007bfc0da1b627577aa32dd73e13e6b8..3b5427d5f3f62e6acfa9bc2bde0bc01334b7ee54 100644 (file)
@@ -47,7 +47,6 @@
 #include "gromacs/fileio/gmxfio.h"
 #include "gromacs/fileio/pdbio.h"
 #include "gromacs/fileio/tngio.h"
-#include "gromacs/fileio/tngio_for_tools.h"
 #include "gromacs/fileio/trxio.h"
 #include "gromacs/fileio/xtcio.h"
 #include "gromacs/fileio/xvgr.h"
@@ -438,7 +437,6 @@ int gmx_trjcat(int argc, char *argv[])
         "the trajectory does not match that in the [REF].xvg[ref] file then the program",
         "tries to be smart. Beware."
     };
-    static gmx_bool bVels           = TRUE;
     static gmx_bool bCat            = FALSE;
     static gmx_bool bSort           = TRUE;
     static gmx_bool bKeepLast       = FALSE;
@@ -459,8 +457,6 @@ int gmx_trjcat(int argc, char *argv[])
           { &end }, "Last time to use (%t)" },
         { "-dt", FALSE, etTIME,
           { &dt }, "Only write frame when t MOD dt = first time (%t)" },
-        { "-vel", FALSE, etBOOL,
-          { &bVels }, "Read and write velocities if possible" },
         { "-settime", FALSE, etBOOL,
           { &bSetTime }, "Change starting time interactively" },
         { "-sort", FALSE, etBOOL,
index aa00fe498f620ee098ab0cad1109b3c9094cad46..f5781ed25c4807156b6af24cca50f7a7711924bb 100644 (file)
@@ -49,7 +49,7 @@
 #include "gromacs/fileio/gmxfio.h"
 #include "gromacs/fileio/groio.h"
 #include "gromacs/fileio/pdbio.h"
-#include "gromacs/fileio/tngio_for_tools.h"
+#include "gromacs/fileio/tngio.h"
 #include "gromacs/fileio/tpxio.h"
 #include "gromacs/fileio/trrio.h"
 #include "gromacs/fileio/trxio.h"
@@ -1244,14 +1244,14 @@ int gmx_trjconv(int argc, char *argv[])
             /* get memory for stuff to go in .pdb file, and initialize
              * the pdbinfo structure part if the input has it.
              */
-            init_t_atoms(&useatoms, atoms->nr, (atoms->pdbinfo != NULL));
+            init_t_atoms(&useatoms, atoms->nr, atoms->havePdbInfo);
             sfree(useatoms.resinfo);
             useatoms.resinfo = atoms->resinfo;
             for (i = 0; (i < nout); i++)
             {
                 useatoms.atomname[i] = atoms->atomname[index[i]];
                 useatoms.atom[i]     = atoms->atom[index[i]];
-                if (atoms->pdbinfo != NULL)
+                if (atoms->havePdbInfo)
                 {
                     useatoms.pdbinfo[i]  = atoms->pdbinfo[index[i]];
                 }
index adf950b8356c4e50042516cc88dff41fe8c391e6..93df67f2503d56645b9b639e869466a2205f8d86 100644 (file)
@@ -56,6 +56,7 @@
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdlib/perf_est.h"
+#include "gromacs/mdrunutility/mdmodules.h"
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
@@ -869,12 +870,13 @@ static void modify_PMEsettings(
         const char     *fn_best_tpr, /* tpr file with the best performance */
         const char     *fn_sim_tpr)  /* name of tpr file to be launched */
 {
-    t_inputrec   *ir;
-    t_state       state;
-    gmx_mtop_t    mtop;
-    char          buf[200];
+    t_inputrec    *ir;
+    t_state        state;
+    gmx_mtop_t     mtop;
+    char           buf[200];
 
-    snew(ir, 1);
+    gmx::MDModules mdModules;
+    ir = mdModules.inputrec();
     read_tpx_state(fn_best_tpr, ir, &state, &mtop);
 
     /* Reset nsteps and init_step to the value of the input .tpr file */
@@ -886,8 +888,6 @@ static void modify_PMEsettings(
     fprintf(stdout, buf, ir->nsteps);
     fflush(stdout);
     write_tpx_state(fn_sim_tpr, ir, &state, &mtop);
-
-    sfree(ir);
 }
 
 static gmx_bool can_scale_rvdw(int vdwtype)
@@ -937,8 +937,8 @@ static void make_benchmark_tprs(
     }
     fprintf(stdout, ".\n");
 
-
-    snew(ir, 1);
+    gmx::MDModules mdModules;
+    ir = mdModules.inputrec();
     read_tpx_state(fn_sim_tpr, ir, &state, &mtop);
 
     /* Check if some kind of PME was chosen */
@@ -1169,7 +1169,6 @@ static void make_benchmark_tprs(
     }
     fflush(stdout);
     fflush(fp);
-    sfree(ir);
 }
 
 
@@ -2047,20 +2046,22 @@ static float inspect_tpr(int nfile, t_filenm fnm[], real *rcoulomb)
     gmx_bool     bFree;     /* Is a free energy simulation requested?         */
     gmx_bool     bNM;       /* Is a normal mode analysis requested?           */
     gmx_bool     bSwap;     /* Is water/ion position swapping requested?      */
-    t_inputrec   ir;
+    t_inputrec  *ir;
     t_state      state;
     gmx_mtop_t   mtop;
 
 
     /* Check tpr file for options that trigger extra output files */
-    read_tpx_state(opt2fn("-s", nfile, fnm), &ir, &state, &mtop);
-    bFree = (efepNO  != ir.efep );
-    bNM   = (eiNM    == ir.eI   );
-    bSwap = (eswapNO != ir.eSwapCoords);
-    bTpi  = EI_TPI(ir.eI);
+    gmx::MDModules mdModules;
+    ir = mdModules.inputrec();
+    read_tpx_state(opt2fn("-s", nfile, fnm), ir, &state, &mtop);
+    bFree = (efepNO  != ir->efep );
+    bNM   = (eiNM    == ir->eI   );
+    bSwap = (eswapNO != ir->eSwapCoords);
+    bTpi  = EI_TPI(ir->eI);
 
     /* Set these output files on the tuning command-line */
-    if (ir.bPull)
+    if (ir->bPull)
     {
         setopt("-pf", nfile, fnm);
         setopt("-px", nfile, fnm);
@@ -2083,10 +2084,11 @@ static float inspect_tpr(int nfile, t_filenm fnm[], real *rcoulomb)
         setopt("-swap", nfile, fnm);
     }
 
-    *rcoulomb = ir.rcoulomb;
+    *rcoulomb = ir->rcoulomb;
 
     /* Return the estimate for the number of PME nodes */
-    return pme_load_estimate(&mtop, &ir, state.box);
+    float npme = pme_load_estimate(&mtop, ir, state.box);
+    return npme;
 }
 
 
index 27e9aa18400153596ec63491037885394e079636..6ed7e737f9c62045967926af5b636b4e88f25234 100644 (file)
@@ -239,6 +239,7 @@ int gmx_velacc(int argc, char *argv[])
     if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME,
                            NFILE, fnm, npargs, ppa, asize(desc), desc, 0, NULL, &oenv))
     {
+        sfree(ppa);
         return 0;
     }
 
index a375cb43648048f3c3d7c998a8e50006ffe0db24..2ae134932d0d1ab8d3811000994991a47b77dcbd 100644 (file)
@@ -44,6 +44,7 @@
 
 #include "config.h"
 
+#include <cassert>
 #include <cctype>
 #include <cmath>
 #include <cstdio>
@@ -60,6 +61,7 @@
 #include "gromacs/math/functions.h"
 #include "gromacs/math/units.h"
 #include "gromacs/math/vec.h"
+#include "gromacs/mdrunutility/mdmodules.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/mdtypes/pull-params.h"
@@ -2049,54 +2051,54 @@ void read_pdo_files(char **fn, int nfiles, t_UmbrellaHeader* header,
 //! 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_coordselection *coordsel)
 {
-    t_inputrec  ir;
-    int         i;
-    t_state     state;
-    static int  first = 1;
+    gmx::MDModules  mdModules;
+    t_inputrec     *ir = mdModules.inputrec();
+    t_state         state;
+    static int      first = 1;
 
     /* printf("Reading %s \n",fn); */
-    read_tpx_state(fn, &ir, &state, NULL);
+    read_tpx_state(fn, ir, &state, NULL);
 
-    if (!ir.bPull)
+    if (!ir->bPull)
     {
         gmx_fatal(FARGS, "This is not a tpr with COM pulling");
     }
-    if (ir.pull->ncoord == 0)
+    if (ir->pull->ncoord == 0)
     {
         gmx_fatal(FARGS, "No pull coordinates found in %s", fn);
     }
 
     /* Read overall pull info */
-    header->npullcrds      = ir.pull->ncoord;
-    header->bPrintCOM      = ir.pull->bPrintCOM;
-    header->bPrintRefValue = ir.pull->bPrintRefValue;
-    header->bPrintComp     = ir.pull->bPrintComp;
+    header->npullcrds      = ir->pull->ncoord;
+    header->bPrintCOM      = ir->pull->bPrintCOM;
+    header->bPrintRefValue = ir->pull->bPrintRefValue;
+    header->bPrintComp     = ir->pull->bPrintComp;
 
     /* Read pull coordinates */
     snew(header->pcrd, header->npullcrds);
-    for (i = 0; i < ir.pull->ncoord; i++)
+    for (int i = 0; i < ir->pull->ncoord; i++)
     {
-        header->pcrd[i].pull_type     = ir.pull->coord[i].eType;
-        header->pcrd[i].geometry      = ir.pull->coord[i].eGeom;
-        header->pcrd[i].ngroup        = ir.pull->coord[i].ngroup;
-        header->pcrd[i].k             = ir.pull->coord[i].k;
-        header->pcrd[i].init_dist     = ir.pull->coord[i].init;
+        header->pcrd[i].pull_type     = ir->pull->coord[i].eType;
+        header->pcrd[i].geometry      = ir->pull->coord[i].eGeom;
+        header->pcrd[i].ngroup        = ir->pull->coord[i].ngroup;
+        header->pcrd[i].k             = ir->pull->coord[i].k;
+        header->pcrd[i].init_dist     = ir->pull->coord[i].init;
 
-        copy_ivec(ir.pull->coord[i].dim, header->pcrd[i].dim);
+        copy_ivec(ir->pull->coord[i].dim, header->pcrd[i].dim);
         header->pcrd[i].ndim         = header->pcrd[i].dim[XX] + header->pcrd[i].dim[YY] + header->pcrd[i].dim[ZZ];
 
         std::strcpy(header->pcrd[i].coord_unit,
-                    pull_coordinate_units(&ir.pull->coord[i]));
+                    pull_coordinate_units(&ir->pull->coord[i]));
 
-        if (ir.efep != efepNO && ir.pull->coord[i].k != ir.pull->coord[i].kB)
+        if (ir->efep != efepNO && ir->pull->coord[i].k != ir->pull->coord[i].kB)
         {
             gmx_fatal(FARGS, "Seems like you did free-energy perturbation, and you perturbed the force constant."
                       " This is not supported.\n");
         }
-        if (coordsel && (coordsel->n != ir.pull->ncoord))
+        if (coordsel && (coordsel->n != ir->pull->ncoord))
         {
             gmx_fatal(FARGS, "Found %d pull coordinates in %s, but %d columns in the respective line\n"
-                      "coordinate selection file (option -is)\n", ir.pull->ncoord, fn, coordsel->n);
+                      "coordinate selection file (option -is)\n", ir->pull->ncoord, fn, coordsel->n);
         }
     }
 
@@ -2104,7 +2106,7 @@ void read_tpr_header(const char *fn, t_UmbrellaHeader* header, t_UmbrellaOptions
     int  geom          = -1;
     ivec thedim        = { 0, 0, 0 };
     bool geometryIsSet = false;
-    for (i = 0; i < ir.pull->ncoord; i++)
+    for (int i = 0; i < ir->pull->ncoord; i++)
     {
         if (coordsel == NULL || coordsel->bUse[i])
         {
@@ -2156,7 +2158,7 @@ void read_tpr_header(const char *fn, t_UmbrellaHeader* header, t_UmbrellaOptions
     {
         printf("\nFile %s, %d coordinates, with these options:\n", fn, header->npullcrds);
         int maxlen = 0;
-        for (i = 0; i < ir.pull->ncoord; i++)
+        for (int i = 0; i < ir->pull->ncoord; i++)
         {
             int lentmp = strlen(epullg_names[header->pcrd[i].geometry]);
             maxlen     = (lentmp > maxlen) ? lentmp : maxlen;
@@ -2164,14 +2166,14 @@ void read_tpr_header(const char *fn, t_UmbrellaHeader* header, t_UmbrellaOptions
         char fmt[STRLEN];
         sprintf(fmt, "\tGeometry %%-%ds  k = %%-8g  position = %%-8g  dimensions [%%s %%s %%s] (%%d dimensions). Used: %%s\n",
                 maxlen+1);
-        for (i = 0; i < ir.pull->ncoord; i++)
+        for (int i = 0; i < ir->pull->ncoord; i++)
         {
             bool use = (coordsel == NULL || coordsel->bUse[i]);
             printf(fmt,
                    epullg_names[header->pcrd[i].geometry], header->pcrd[i].k, header->pcrd[i].init_dist,
                    int2YN(header->pcrd[i].dim[XX]), int2YN(header->pcrd[i].dim[YY]), int2YN(header->pcrd[i].dim[ZZ]),
                    header->pcrd[i].ndim, use ? "Yes" : "No");
-            printf("\tPull group coordinates of %d groups expected in pullx files.\n", ir.pull->bPrintCOM ? header->pcrd[i].ngroup : 0);
+            printf("\tPull group coordinates of %d groups expected in pullx files.\n", ir->pull->bPrintCOM ? header->pcrd[i].ngroup : 0);
         }
         printf("\tReference value of the coordinate%s expected in pullx files.\n",
                header->bPrintRefValue ? "" : " not");
@@ -2294,6 +2296,7 @@ void read_pull_xf(const char *fn, t_UmbrellaHeader * header,
 
     if (!bGetMinMax)
     {
+        assert(window);
         bins = opt->bins;
         min  = opt->min;
         max  = opt->max;
index af7a8080babb424ed4761fab9c4ca95f2cee4d02..558aa174a28af6bd114942f151dfe315feb45693 100644 (file)
@@ -32,7 +32,6 @@
 # To help us fund GROMACS development, we humbly ask that you cite
 # the research papers on the package. Check out http://www.gromacs.org.
 
-set(testname "LegacyToolsTests")
 set(exename "legacy-tools-test")
 
 gmx_add_gtest_executable(
@@ -40,7 +39,4 @@ gmx_add_gtest_executable(
     # files with code for test fixtures
     gmx_traj_tests.cpp
     )
-gmx_register_integration_test(
-    ${testname}
-    ${exename}
-    )
+gmx_register_gtest_test(LegacyToolsTest ${exename} INTEGRATION_TEST)
index 820ba06471a4b5240145e1de0f9a584bff3e3546..6ac20f7a110827b3dc5b2460e7ad2f14d5ed0b31 100644 (file)
@@ -150,10 +150,6 @@ const char *trajectoryFileNames[] = {
     "spc2-traj.g96"
 };
 
-#ifdef __INTEL_COMPILER
-#pragma warning( disable : 177 )
-#endif
-
 INSTANTIATE_TEST_CASE_P(NoFatalErrorWhenWritingFrom,
                         GmxTraj,
                             ::testing::ValuesIn(gmx::ArrayRef<const char*>(trajectoryFileNames)));
index 5b58fdd8d9aed72a82d84c2a798b04b19ba2a743..5759488a5472586857e67802534b50b4da614bbc 100644 (file)
@@ -41,6 +41,8 @@
 #include <cstdlib>
 #include <cstring>
 
+#include <algorithm>
+
 #include "gromacs/listed-forces/bonded.h"
 #include "gromacs/pbcutil/rmpbc.h"
 #include "gromacs/utility/cstringutil.h"
 static const char *pp_pat[] = { "C", "N", "CA", "C", "N" };
 #define NPP (sizeof(pp_pat)/sizeof(pp_pat[0]))
 
-static int d_comp(const void *a, const void *b)
+static bool d_comp(const t_dih &a, const t_dih &b)
 {
-    t_dih *da, *db;
-
-    da = (t_dih *)a;
-    db = (t_dih *)b;
-
-    if (da->ai[1] < db->ai[1])
+    if (a.ai[1] < b.ai[1])
     {
-        return -1;
+        return true;
     }
-    else if (da->ai[1] == db->ai[1])
+    else if (a.ai[1] == b.ai[1])
     {
-        return (da->ai[2] - db->ai[2]);
+        return a.ai[2] < b.ai[2];
     }
     else
     {
-        return 1;
+        return false;
     }
 }
 
@@ -217,8 +214,8 @@ static void get_dih_props(t_xrama *xr, const t_idef *idef, int mult)
 
         key.ai[1] = ia[2];
         key.ai[2] = ia[3];
-        if ((dd = (t_dih *)bsearch(&key, xr->dih, xr->ndih, (size_t)sizeof(key), d_comp))
-            != NULL)
+        dd        = std::lower_bound(xr->dih, xr->dih+xr->ndih, key, d_comp);
+        if (dd < xr->dih+xr->ndih && !d_comp(key, *dd))
         {
             dd->mult = idef->iparams[ft].pdihs.mult;
             dd->phi0 = idef->iparams[ft].pdihs.phiA;
index dd9a9ab8f380153c9892d2e8af0bfb4034e4f121..4b7e7356caa98c0fc26f12c083aa6042775af745 100644 (file)
@@ -148,7 +148,7 @@ gmx_neutron_atomic_structurefactors_t *gmx_neutronstructurefactors_init(const ch
 
     fclose(fp);
 
-    return (gmx_neutron_atomic_structurefactors_t *) gnsf;
+    return gnsf;
 }
 
 gmx_sans_t *gmx_sans_init (const t_topology *top, gmx_neutron_atomic_structurefactors_t *gnsf)
@@ -186,7 +186,7 @@ gmx_sans_t *gmx_sans_init (const t_topology *top, gmx_neutron_atomic_structurefa
         }
     }
 
-    return (gmx_sans_t *) gsans;
+    return gsans;
 }
 
 gmx_radial_distribution_histogram_t *calc_radial_distribution_histogram (
@@ -364,7 +364,7 @@ gmx_radial_distribution_histogram_t *calc_radial_distribution_histogram (
         pr->r[i] = (pr->binwidth*i+pr->binwidth*0.5);
     }
 
-    return (gmx_radial_distribution_histogram_t *) pr;
+    return pr;
 }
 
 gmx_static_structurefactor_t *convert_histogram_to_intensity_curve (gmx_radial_distribution_histogram_t *pr, double start_q, double end_q, double q_step)
@@ -405,5 +405,5 @@ gmx_static_structurefactor_t *convert_histogram_to_intensity_curve (gmx_radial_d
         }
     }
 
-    return (gmx_static_structurefactor_t *) sq;
+    return sq;
 }
index 2a2cf40dd5097463dd186c20fe39853bd6baa84b..f6ddd9a1f0de240b7fb01db408f6145e40219a79 100644 (file)
@@ -111,6 +111,34 @@ t_commrec *init_commrec()
     return cr;
 }
 
+static void done_mpi_in_place_buf(mpi_in_place_buf_t *buf)
+{
+    if (NULL != buf)
+    {
+        sfree(buf->ibuf);
+        sfree(buf->libuf);
+        sfree(buf->fbuf);
+        sfree(buf->dbuf);
+        sfree(buf);
+    }
+}
+
+void done_commrec(t_commrec *cr)
+{
+    if (NULL != cr->dd)
+    {
+        // TODO: implement
+        // done_domdec(cr->dd);
+    }
+    if (NULL != cr->ms)
+    {
+        done_mpi_in_place_buf(cr->ms->mpb);
+        sfree(cr->ms);
+    }
+    done_mpi_in_place_buf(cr->mpb);
+    sfree(cr);
+}
+
 t_commrec *reinitialize_commrec_for_this_thread(const t_commrec gmx_unused *cro)
 {
 #if GMX_THREAD_MPI
@@ -720,6 +748,7 @@ void gmx_fatal_collective(int f_errno, const char *file, int line,
     /* Any result except MPI_UNEQUAL allows us to call MPI_Finalize */
     bFinalize = (result != MPI_UNEQUAL);
 #else
+    GMX_UNUSED_VALUE(comm);
     bFinalize = TRUE;
 #endif
 
index f362475c511618f922d8f511da71aab39c60a57d..78b637e76a9e6c8a5f96e1e2c836d90fd4662928 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -53,6 +53,9 @@ struct t_filenm;
 struct t_commrec *init_commrec(void);
 /* Allocate, initialize and return the commrec. */
 
+void done_commrec(struct t_commrec *cr);
+/* Free memory associated with the commrec. */
+
 struct t_commrec *reinitialize_commrec_for_this_thread(const struct t_commrec *cro);
 /* Initialize communication records for thread-parallel simulations.
    Must be called on all threads before any communication takes place by
index 25a7c83cd10314751b82eefa2c1cfac703c80d33..9285b21fa40f6bc6e25809cb8b16db1af4855178 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 #define gmx_mm_castsi128_ps   _mm_castsi128_ps
 #define gmx_mm_extract_epi32  _mm_extract_epi32
 
-/* Work around gcc bug with wrong type for mask formal parameter to maskload/maskstore */
-#if GMX_SIMD_X86_AVX_GCC_MASKLOAD_BUG
-#    define gmx_mm_maskload_ps(mem, mask)       _mm_maskload_ps((mem), _mm_castsi128_ps(mask))
-#    define gmx_mm_maskstore_ps(mem, mask, x)    _mm_maskstore_ps((mem), _mm_castsi128_ps(mask), (x))
-#    define gmx_mm256_maskload_ps(mem, mask)    _mm256_maskload_ps((mem), _mm256_castsi256_ps(mask))
-#    define gmx_mm256_maskstore_ps(mem, mask, x) _mm256_maskstore_ps((mem), _mm256_castsi256_ps(mask), (x))
-#else
-#    define gmx_mm_maskload_ps(mem, mask)       _mm_maskload_ps((mem), (mask))
-#    define gmx_mm_maskstore_ps(mem, mask, x)    _mm_maskstore_ps((mem), (mask), (x))
-#    define gmx_mm256_maskload_ps(mem, mask)    _mm256_maskload_ps((mem), (mask))
-#    define gmx_mm256_maskstore_ps(mem, mask, x) _mm256_maskstore_ps((mem), (mask), (x))
-#endif
+#define gmx_mm_maskload_ps(mem, mask)       _mm_maskload_ps((mem), (mask))
+#define gmx_mm_maskstore_ps(mem, mask, x)    _mm_maskstore_ps((mem), (mask), (x))
+#define gmx_mm256_maskload_ps(mem, mask)    _mm256_maskload_ps((mem), (mask))
+#define gmx_mm256_maskstore_ps(mem, mask, x) _mm256_maskstore_ps((mem), (mask), (x))
 
 /* Normal sum of four xmm registers */
 #define gmx_mm_sum4_ps(t0, t1, t2, t3)  _mm_add_ps(_mm_add_ps(t0, t1), _mm_add_ps(t2, t3))
index bfbccd54deced3623f0ebebcc4a5dd52f8a6c821..ac489ea64b21db84737e635db5af0bfbbf9dca0c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -59,18 +59,10 @@ gmx_mm256_set_m128(__m128 hi, __m128 lo)
     return _mm256_insertf128_ps(_mm256_castps128_ps256(lo), hi, 0x1);
 }
 
-/* Work around gcc bug with wrong type for mask formal parameter to maskload/maskstore */
-#if GMX_SIMD_X86_AVX_GCC_MASKLOAD_BUG
-#    define gmx_mm_maskload_ps(mem, mask)       _mm_maskload_ps((mem), _mm_castsi128_ps(mask))
-#    define gmx_mm_maskstore_ps(mem, mask, x)    _mm_maskstore_ps((mem), _mm_castsi128_ps(mask), (x))
-#    define gmx_mm256_maskload_ps(mem, mask)    _mm256_maskload_ps((mem), _mm256_castsi256_ps(mask))
-#    define gmx_mm256_maskstore_ps(mem, mask, x) _mm256_maskstore_ps((mem), _mm256_castsi256_ps(mask), (x))
-#else
-#    define gmx_mm_maskload_ps(mem, mask)       _mm_maskload_ps((mem), (mask))
-#    define gmx_mm_maskstore_ps(mem, mask, x)    _mm_maskstore_ps((mem), (mask), (x))
-#    define gmx_mm256_maskload_ps(mem, mask)    _mm256_maskload_ps((mem), (mask))
-#    define gmx_mm256_maskstore_ps(mem, mask, x) _mm256_maskstore_ps((mem), (mask), (x))
-#endif
+#define gmx_mm_maskload_ps(mem, mask)       _mm_maskload_ps((mem), (mask))
+#define gmx_mm_maskstore_ps(mem, mask, x)    _mm_maskstore_ps((mem), (mask), (x))
+#define gmx_mm256_maskload_ps(mem, mask)    _mm256_maskload_ps((mem), (mask))
+#define gmx_mm256_maskstore_ps(mem, mask, x) _mm256_maskstore_ps((mem), (mask), (x))
 
 /* Transpose lower/upper half of 256-bit registers separately */
 #define GMX_MM256_HALFTRANSPOSE4_PS(ymm0, ymm1, ymm2, ymm3) {            \
index 94dee2656415fada44214041c1d451082457b8c1..d2660bc772e4f7e2b45b18c577aa8e742ada6f01 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -41,6 +41,7 @@
 
 #include <string.h>
 
+#include <cassert>
 #include <cmath>
 
 #include "gromacs/gmxpreprocess/gpp_atomtype.h"
@@ -560,6 +561,7 @@ static void enter_function(t_params *p, t_functype ftype, int comb, real reppow,
         /* Type==-1 is used as a signal that this interaction is all-zero and should not be added. */
         if (!bNB && type >= 0)
         {
+            assert(il);
             nral  = NRAL(ftype);
             delta = nr*(nral+1);
             srenew(il->iatoms, il->nr+delta);
index ee7bf4cc3847401da96937dbf00b0187c6371e92..ed7ccdec712c785a685b0fb2d2190d1fcde2f1ee 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -61,7 +61,7 @@
 #include "gromacs/utility/smalloc.h"
 
 #define DIHEDRAL_WAS_SET_IN_RTP 0
-static gmx_bool was_dihedral_set_in_rtp(t_param *dih)
+static gmx_bool was_dihedral_set_in_rtp(const t_param *dih)
 {
     return dih->c[MAXFORCEPARAM-1] == DIHEDRAL_WAS_SET_IN_RTP;
 }
@@ -70,11 +70,11 @@ typedef gmx_bool (*peq)(t_param *p1, t_param *p2);
 
 static int acomp(const void *a1, const void *a2)
 {
-    t_param *p1, *p2;
-    int      ac;
+    const t_param *p1, *p2;
+    int            ac;
 
-    p1 = (t_param *)a1;
-    p2 = (t_param *)a2;
+    p1 = static_cast<const t_param *>(a1);
+    p2 = static_cast<const t_param *>(a2);
     if ((ac = (p1->aj()-p2->aj())) != 0)
     {
         return ac;
@@ -91,11 +91,11 @@ static int acomp(const void *a1, const void *a2)
 
 static int pcomp(const void *a1, const void *a2)
 {
-    t_param *p1, *p2;
-    int      pc;
+    const t_param *p1, *p2;
+    int            pc;
 
-    p1 = (t_param *)a1;
-    p2 = (t_param *)a2;
+    p1 = static_cast<const t_param *>(a1);
+    p2 = static_cast<const t_param *>(a2);
     if ((pc = (p1->ai()-p2->ai())) != 0)
     {
         return pc;
@@ -108,11 +108,11 @@ static int pcomp(const void *a1, const void *a2)
 
 static int dcomp(const void *d1, const void *d2)
 {
-    t_param *p1, *p2;
-    int      dc;
+    const t_param *p1, *p2;
+    int            dc;
 
-    p1 = (t_param *)d1;
-    p2 = (t_param *)d2;
+    p1 = static_cast<const t_param *>(d1);
+    p2 = static_cast<const t_param *>(d2);
     /* First sort by J & K (the two central) atoms */
     if ((dc = (p1->aj()-p2->aj())) != 0)
     {
@@ -306,11 +306,11 @@ static int int_comp(const void *a, const void *b)
 
 static int idcomp(const void *a, const void *b)
 {
-    t_param *pa, *pb;
-    int      d;
+    const t_param *pa, *pb;
+    int            d;
 
-    pa = (t_param *)a;
-    pb = (t_param *)b;
+    pa = static_cast<const t_param *>(a);
+    pb = static_cast<const t_param *>(b);
     if ((d = (pa->a[0]-pb->a[0])) != 0)
     {
         return d;
index 6f25a14da8bc8516f72d0df0d6055c4bdbfdce17..350e1ad95176a82c4f356cf4e4cd1e7e346be393 100644 (file)
@@ -57,7 +57,7 @@ static void low_mspeed(real tempi,
     real                                    boltz, sd;
     real                                    ekin, temp, mass, scal;
     gmx_mtop_atomloop_all_t                 aloop;
-    t_atom                                 *atom;
+    const t_atom                           *atom;
     gmx::TabulatedNormalDistribution<real>  normalDist;
 
     boltz = BOLTZ*tempi;
index 7759c00cd49f15f28107d717608fa3f13d61c296..807e5323cf85c18ecf784791182d65955dc81456 100644 (file)
@@ -313,5 +313,15 @@ int gmx_genconf(int argc, char *argv[])
 
     write_sto_conf(opt2fn("-o", NFILE, fnm), *top->name, atoms, x, v, ePBC, box);
 
+    sfree(x);
+    sfree(v);
+    sfree(xrot);
+    sfree(vrot);
+    sfree(xx);
+    done_top(top);
+    sfree(top);
+    done_filenms(NFILE, fnm);
+    output_env_done(oenv);
+
     return 0;
 }
index 913afe9233f84ec0d839aab8ae6cc8580c45642f..d93b55b74a7c00ed2fb083ae42acb0bce1a09e3f 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -63,10 +63,15 @@ typedef struct {
     real       c[MAXFORCEPARAM]; /* Force parameters (eg. b0 = c[0])   */
     char       s[MAXSLEN];       /* A string (instead of parameters),    *
                                   * read from the .rtp file in pdb2gmx   */
+    const int &ai() const { return a[0]; }
     int   &ai() { return a[0]; }
+    const int &aj() const { return a[1]; }
     int   &aj() { return a[1]; }
+    const int &ak() const { return a[2]; }
     int   &ak() { return a[2]; }
+    const int &al() const { return a[3]; }
     int   &al() { return a[3]; }
+    const int &am() const { return a[4]; }
     int   &am() { return a[4]; }
 
     real      &c0() { return c[0]; }
index cd4ee3af4b32efec9a78009825dd8e8a9f2fc6cc..e5ab2360cd3dbcd6cf3dda4c4a63e2fd3c8364e3 100644 (file)
@@ -75,6 +75,7 @@
 #include "gromacs/mdlib/compute_io.h"
 #include "gromacs/mdlib/genborn.h"
 #include "gromacs/mdlib/perf_est.h"
+#include "gromacs/mdrunutility/mdmodules.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/mdtypes/nblist.h"
@@ -362,7 +363,7 @@ static void check_bonds_timestep(gmx_mtop_t *mtop, double dt, warninp_t wi)
 static void check_vel(gmx_mtop_t *mtop, rvec v[])
 {
     gmx_mtop_atomloop_all_t aloop;
-    t_atom                 *atom;
+    const t_atom           *atom;
     int                     a;
 
     aloop = gmx_mtop_atomloop_all_init(mtop);
@@ -382,7 +383,7 @@ static void check_shells_inputrec(gmx_mtop_t *mtop,
                                   warninp_t   wi)
 {
     gmx_mtop_atomloop_all_t aloop;
-    t_atom                 *atom;
+    const t_atom           *atom;
     int                     a, nshells = 0;
     char                    warn_buf[STRLEN];
 
@@ -602,16 +603,38 @@ new_status(const char *topfile, const char *topppfile, const char *confin,
     }
 
     t_topology *conftop;
+    rvec       *x = NULL;
+    rvec       *v = NULL;
     snew(conftop, 1);
     init_state(state, 0, 0, 0, 0, 0);
-    read_tps_conf(confin, conftop, NULL, &state->x, &state->v, state->box, FALSE);
-    state->natoms = state->nalloc = conftop->atoms.nr;
+    read_tps_conf(confin, conftop, NULL, &x, &v, state->box, FALSE);
+    state->natoms = conftop->atoms.nr;
     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);
     }
+    /* It would be nice to get rid of the copies below, but we don't know
+     * a priori if the number of atoms in confin matches what we expect.
+     */
+    state->flags |= (1 << estX);
+    state->x.resize(state->natoms);
+    for (int i = 0; i < state->natoms; i++)
+    {
+        copy_rvec(x[i], state->x[i]);
+    }
+    sfree(x);
+    if (v != NULL)
+    {
+        state->flags |= (1 << estV);
+        state->v.resize(state->natoms);
+        for (int i = 0; i < state->natoms; i++)
+        {
+            copy_rvec(v[i], state->v[i]);
+        }
+        sfree(v);
+    }
     /* This call fixes the box shape for runs with pressure scaling */
     set_box_rel(ir, state);
 
@@ -647,7 +670,7 @@ new_status(const char *topfile, const char *topppfile, const char *confin,
     {
         real                   *mass;
         gmx_mtop_atomloop_all_t aloop;
-        t_atom                 *atom;
+        const t_atom           *atom;
 
         snew(mass, state->natoms);
         aloop = gmx_mtop_atomloop_all_init(sys);
@@ -661,9 +684,10 @@ new_status(const char *topfile, const char *topppfile, const char *confin,
             opts->seed = static_cast<int>(gmx::makeRandomSeed());
             fprintf(stderr, "Setting gen_seed to %d\n", opts->seed);
         }
-        maxwell_speed(opts->tempi, opts->seed, sys, state->v);
+        state->flags |= (1 << estV);
+        maxwell_speed(opts->tempi, opts->seed, sys, as_rvec_array(state->v.data()));
 
-        stop_cm(stdout, state->natoms, mass, state->x, state->v);
+        stop_cm(stdout, state->natoms, mass, as_rvec_array(state->x.data()), as_rvec_array(state->v.data()));
         sfree(mass);
     }
 
@@ -1302,7 +1326,7 @@ static real calc_temp(const gmx_mtop_t *mtop,
                       rvec             *v)
 {
     gmx_mtop_atomloop_all_t aloop;
-    t_atom                 *atom;
+    const t_atom           *atom;
     int                     a;
 
     double                  sum_mv2 = 0;
@@ -1575,7 +1599,6 @@ int gmx_grompp(int argc, char *argv[])
     t_inputrec        *ir;
     int                nvsite, comb, mt;
     t_params          *plist;
-    t_state           *state;
     matrix             box;
     real               fudgeQQ;
     double             reppow;
@@ -1627,11 +1650,6 @@ int gmx_grompp(int argc, char *argv[])
           "Renumber atomtypes and minimize number of atomtypes" }
     };
 
-    /* Initiate some variables */
-    snew(ir, 1);
-    snew(opts, 1);
-    init_ir(ir, opts);
-
     /* Parse the command line */
     if (!parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa), pa,
                            asize(desc), desc, 0, NULL, &oenv))
@@ -1639,6 +1657,12 @@ int gmx_grompp(int argc, char *argv[])
         return 0;
     }
 
+    /* Initiate some variables */
+    gmx::MDModules mdModules;
+    ir = mdModules.inputrec();
+    snew(opts, 1);
+    init_ir(ir, opts);
+
     wi = init_warning(TRUE, maxwarn);
 
     /* PARAMETER file processing */
@@ -1689,9 +1713,10 @@ int gmx_grompp(int argc, char *argv[])
     {
         gmx_fatal(FARGS, "%s does not exist", fn);
     }
-    snew(state, 1);
+
+    t_state state {};
     new_status(fn, opt2fn_null("-pp", NFILE, fnm), opt2fn("-c", NFILE, fnm),
-               opts, ir, bZero, bGenVel, bVerbose, state,
+               opts, ir, bZero, bGenVel, bVerbose, &state,
                atype, sys, &nmi, &mi, &intermolecular_interactions,
                plist, &comb, &reppow, &fudgeQQ,
                opts->bMorse,
@@ -1868,7 +1893,7 @@ int gmx_grompp(int argc, char *argv[])
     /* Check velocity for virtual sites and shells */
     if (bGenVel)
     {
-        check_vel(sys, state->v);
+        check_vel(sys, as_rvec_array(state.v.data()));
     }
 
     /* check for shells and inpurecs */
@@ -1918,7 +1943,7 @@ int gmx_grompp(int argc, char *argv[])
                 }
                 else
                 {
-                    buffer_temp = calc_temp(sys, ir, state->v);
+                    buffer_temp = calc_temp(sys, ir, as_rvec_array(state.v.data()));
                 }
                 if (buffer_temp > 0)
                 {
@@ -1973,13 +1998,13 @@ int gmx_grompp(int argc, char *argv[])
                     }
                 }
 
-                set_verlet_buffer(sys, ir, buffer_temp, state->box, wi);
+                set_verlet_buffer(sys, ir, buffer_temp, state.box, wi);
             }
         }
     }
 
     /* Init the temperature coupling state */
-    init_gtc_state(state, ir->opts.ngtc, 0, ir->opts.nhchainlength); /* need to add nnhpres here? */
+    init_gtc_state(&state, ir->opts.ngtc, 0, ir->opts.nhchainlength); /* need to add nnhpres here? */
 
     if (bVerbose)
     {
@@ -2019,24 +2044,24 @@ int gmx_grompp(int argc, char *argv[])
             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);
+                    bNeedVel, bGenVel, fr_time, ir, &state, sys, oenv);
     }
 
     if (ir->ePBC == epbcXY && ir->nwall != 2)
     {
-        clear_rvec(state->box[ZZ]);
+        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);
+        check_chargegroup_radii(sys, ir, as_rvec_array(state.x.data()), wi);
     }
 
     if (EEL_FULL(ir->coulombtype) || EVDW_PME(ir->vdwtype))
     {
         /* Calculate the optimal grid dimensions */
-        copy_mat(state->box, box);
+        copy_mat(state.box, box);
         if (ir->ePBC == epbcXY && ir->nwall == 2)
         {
             svmul(ir->wall_ewald_zfac, box[ZZ], box[ZZ]);
@@ -2060,13 +2085,13 @@ int gmx_grompp(int argc, char *argv[])
        potentially conflict if not handled correctly. */
     if (ir->efep != efepNO)
     {
-        state->fep_state = ir->fepvals->init_fep_state;
+        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;
+                state.lambda[i] = ir->fepvals->init_lambda;
             }
             else
             {
@@ -2076,7 +2101,7 @@ int gmx_grompp(int argc, char *argv[])
                 }
                 else
                 {
-                    state->lambda[i] = ir->fepvals->all_lambda[i][state->fep_state];
+                    state.lambda[i] = ir->fepvals->all_lambda[i][state.fep_state];
                 }
             }
         }
@@ -2086,7 +2111,7 @@ int gmx_grompp(int argc, char *argv[])
 
     if (ir->bPull)
     {
-        pull = set_pull_init(ir, sys, state->x, state->box, state->lambda[efptMASS], oenv);
+        pull = set_pull_init(ir, sys, as_rvec_array(state.x.data()), state.box, state.lambda[efptMASS], oenv);
     }
 
     /* Modules that supply external potential for pull coordinates
@@ -2101,7 +2126,7 @@ int gmx_grompp(int argc, char *argv[])
 
     if (ir->bRot)
     {
-        set_reference_positions(ir->rot, state->x, state->box,
+        set_reference_positions(ir->rot, as_rvec_array(state.x.data()), state.box,
                                 opt2fn("-ref", NFILE, fnm), opt2bSet("-ref", NFILE, fnm),
                                 wi);
     }
@@ -2110,7 +2135,7 @@ int gmx_grompp(int argc, char *argv[])
 
     if (EEL_PME(ir->coulombtype))
     {
-        float ratio = pme_load_estimate(sys, ir, state->box);
+        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
@@ -2152,15 +2177,13 @@ int gmx_grompp(int argc, char *argv[])
     }
 
     done_warning(wi, FARGS);
-    write_tpx_state(ftp2fn(efTPR, NFILE, fnm), ir, state, sys);
+    write_tpx_state(ftp2fn(efTPR, NFILE, fnm), ir, &state, sys);
 
     /* Output IMD group, if bIMD is TRUE */
-    write_IMDgroup_to_file(ir->bIMD, ir, state, sys, NFILE, fnm);
+    write_IMDgroup_to_file(ir->bIMD, ir, &state, sys, NFILE, fnm);
 
-    done_state(state);
-    sfree(state);
     done_atomtype(atype);
-    done_mtop(sys, TRUE);
+    done_mtop(sys);
     done_inputrec_strings();
 
     return 0;
index 61cb60f705c6dc55c160ba784872572e9c4655db..50dee9d5e0a558c77140bf1478ecfeef2c0b186f 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -63,10 +63,10 @@ const int ncontrol[] = { -1, 3, 3, 3, 3, 4, 3, 1, 3, 3, 1, 1 };
 
 int compaddh(const void *a, const void *b)
 {
-    t_hackblock *ah, *bh;
+    const t_hackblock *ah, *bh;
 
-    ah = (t_hackblock *)a;
-    bh = (t_hackblock *)b;
+    ah = static_cast<const t_hackblock *>(a);
+    bh = static_cast<const t_hackblock *>(b);
     return gmx_strcasecmp(ah->name, bh->name);
 }
 
@@ -240,7 +240,7 @@ t_hackblock *search_h_db(int nh, t_hackblock ah[], char *key)
 
     ahkey.name = key;
 
-    result = (t_hackblock *)bsearch(&ahkey, ah, nh, (size_t)sizeof(ah[0]), compaddh);
+    result = static_cast<t_hackblock *>(bsearch(&ahkey, ah, nh, (size_t)sizeof(ah[0]), compaddh));
 
     return result;
 }
index 20fb243157946eab7e6eec7fbf0512ad7face918..936dd144db6889ed0c21aa12f93442ec54363a59 100644 (file)
@@ -67,6 +67,7 @@
 #include "gromacs/topology/atomprop.h"
 #include "gromacs/topology/atoms.h"
 #include "gromacs/topology/atomsbuilder.h"
+#include "gromacs/topology/mtop_util.h"
 #include "gromacs/topology/topology.h"
 #include "gromacs/trajectory/trajectoryframe.h"
 #include "gromacs/utility/cstringutil.h"
@@ -163,7 +164,7 @@ static bool isInsertionAllowed(gmx::AnalysisNeighborhoodSearch *search,
 
 static void insert_mols(int nmol_insrt, int ntry, int seed,
                         real defaultDistance, real scaleFactor,
-                        t_topology *top, std::vector<RVec> *x,
+                        t_atoms *atoms, t_symtab *symtab, std::vector<RVec> *x,
                         const std::set<int> &removableAtoms,
                         const t_atoms &atoms_insrt, const std::vector<RVec> &x_insrt,
                         int ePBC, matrix box,
@@ -173,7 +174,7 @@ static void insert_mols(int nmol_insrt, int ntry, int seed,
     fprintf(stderr, "Initialising inter-atomic distances...\n");
     gmx_atomprop_t          aps = gmx_atomprop_init();
     std::vector<real>       exclusionDistances(
-            makeExclusionDistances(&top->atoms, aps, defaultDistance, scaleFactor));
+            makeExclusionDistances(atoms, aps, defaultDistance, scaleFactor));
     const std::vector<real> exclusionDistances_insrt(
             makeExclusionDistances(&atoms_insrt, aps, defaultDistance, scaleFactor));
     gmx_atomprop_destroy(aps);
@@ -222,11 +223,11 @@ static void insert_mols(int nmol_insrt, int ntry, int seed,
                 nmol_insrt, posfn.c_str());
     }
 
-    gmx::AtomsBuilder builder(&top->atoms, &top->symtab);
-    gmx::AtomsRemover remover(top->atoms);
+    gmx::AtomsBuilder builder(atoms, symtab);
+    gmx::AtomsRemover remover(*atoms);
     {
-        const int finalAtomCount    = top->atoms.nr + nmol_insrt * atoms_insrt.nr;
-        const int finalResidueCount = top->atoms.nres + nmol_insrt * atoms_insrt.nres;
+        const int finalAtomCount    = atoms->nr + nmol_insrt * atoms_insrt.nr;
+        const int finalResidueCount = atoms->nres + nmol_insrt * atoms_insrt.nres;
         builder.reserve(finalAtomCount, finalResidueCount);
         x->reserve(finalAtomCount);
         exclusionDistances.reserve(finalAtomCount);
@@ -276,7 +277,7 @@ static void insert_mols(int nmol_insrt, int ntry, int seed,
         gmx::AnalysisNeighborhoodPositions pos(*x);
         gmx::AnalysisNeighborhoodSearch    search = nb.initSearch(&pbc, pos);
         if (isInsertionAllowed(&search, exclusionDistances, x_n, exclusionDistances_insrt,
-                               top->atoms, removableAtoms, &remover))
+                               *atoms, removableAtoms, &remover))
         {
             x->insert(x->end(), x_n.begin(), x_n.end());
             exclusionDistances.insert(exclusionDistances.end(),
@@ -294,16 +295,16 @@ static void insert_mols(int nmol_insrt, int ntry, int seed,
     fprintf(stderr, "Added %d molecules (out of %d requested)\n",
             mol - failed, nmol_insrt);
 
-    const int originalAtomCount    = top->atoms.nr;
-    const int originalResidueCount = top->atoms.nres;
-    remover.refreshAtomCount(top->atoms);
+    const int originalAtomCount    = atoms->nr;
+    const int originalResidueCount = atoms->nres;
+    remover.refreshAtomCount(*atoms);
     remover.removeMarkedElements(x);
-    remover.removeMarkedAtoms(&top->atoms);
-    if (top->atoms.nr < originalAtomCount)
+    remover.removeMarkedAtoms(atoms);
+    if (atoms->nr < originalAtomCount)
     {
         fprintf(stderr, "Replaced %d residues (%d atoms)\n",
-                originalResidueCount - top->atoms.nres,
-                originalAtomCount - top->atoms.nr);
+                originalResidueCount - atoms->nres,
+                originalAtomCount - atoms->nr);
     }
 
     if (rpos != NULL)
@@ -338,13 +339,13 @@ class InsertMolecules : public ICommandLineOptionsModule, public ITopologyProvid
         {
             if (top_ != NULL)
             {
-                done_top(top_);
+                done_mtop(top_);
                 sfree(top_);
             }
         }
 
         // From ITopologyProvider
-        virtual t_topology *getTopology(bool /*required*/) { return top_; }
+        virtual gmx_mtop_t *getTopology(bool /*required*/) { return top_; }
         virtual int getAtomCount() { return 0; }
 
         // From ICommandLineOptionsModule
@@ -376,7 +377,7 @@ class InsertMolecules : public ICommandLineOptionsModule, public ITopologyProvid
         RotationType        enumRot_;
         Selection           replaceSel_;
 
-        t_topology         *top_;
+        gmx_mtop_t         *top_;
         std::vector<RVec>   x_;
         matrix              box_;
         int                 ePBC_;
@@ -510,7 +511,7 @@ void InsertMolecules::optionsFinished()
     {
         readConformation(inputConfFile_.c_str(), top_, &x_, NULL,
                          &ePBC_, box_, "solute");
-        if (top_->atoms.nr == 0)
+        if (top_->natoms == 0)
         {
             fprintf(stderr, "Note: no atoms in %s\n", inputConfFile_.c_str());
         }
@@ -575,22 +576,26 @@ int InsertMolecules::run()
         }
     }
 
+    // TODO: Adapt to use mtop throughout.
+    t_atoms atoms = gmx_mtop_global_atoms(top_);
+
     /* add nmol_ins molecules of atoms_ins
        in random orientation at random place */
     insert_mols(nmolIns_, nmolTry_, seed_, defaultDistance_, scaleFactor_,
-                top_, &x_, removableAtoms, top_insrt->atoms, x_insrt,
+                &atoms, &top_->symtab, &x_, removableAtoms, top_insrt->atoms, x_insrt,
                 ePBC_, box_, positionFile_, deltaR_, enumRot_);
 
     /* write new configuration to file confout */
     fprintf(stderr, "Writing generated configuration to %s\n",
             outputConfFile_.c_str());
-    write_sto_conf(outputConfFile_.c_str(), *top_->name, &top_->atoms,
+    write_sto_conf(outputConfFile_.c_str(), *top_->name, &atoms,
                    as_rvec_array(x_.data()), NULL, ePBC_, box_);
 
     /* print size of generated configuration */
     fprintf(stderr, "\nOutput configuration contains %d atoms in %d residues\n",
-            top_->atoms.nr, top_->atoms.nres);
+            atoms.nr, atoms.nres);
 
+    done_atom(&atoms);
     done_top(top_insrt);
     sfree(top_insrt);
 
index ff2f86e5705c5462c4bfe7e69395c8fb864db49e..9943fe4cc24ae44cee7c8cda68b580e9968d1291 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -226,7 +226,7 @@ choose_ff_impl(const char *ffsel,
                 FILE *fp = gmx_ffopen(docFileName.c_str(), "r");
                 get_a_line(fp, buf, STRLEN);
                 gmx_ffclose(fp);
-                desc.push_back(buf);
+                desc.emplace_back(buf);
             }
             else
             {
@@ -843,10 +843,10 @@ static void at2bonds(t_params *psb, t_hackblock *hb,
 
 static int pcompar(const void *a, const void *b)
 {
-    t_param *pa, *pb;
-    int      d;
-    pa = (t_param *)a;
-    pb = (t_param *)b;
+    const t_param *pa, *pb;
+    int            d;
+    pa = static_cast<const t_param *>(a);
+    pb = static_cast<const t_param *>(b);
 
     d = pa->a[0] - pb->a[0];
     if (d == 0)
index de1a1ebeb0eef240201235fe29ad0940427b7a98..0d025476b7a70872105d7be4d8ca95054508f716 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -41,6 +41,7 @@
 #include "gromacs/fileio/confio.h"
 #include "gromacs/topology/atomprop.h"
 #include "gromacs/topology/atoms.h"
+#include "gromacs/topology/mtop_util.h"
 #include "gromacs/topology/topology.h"
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/scoped_cptr.h"
@@ -73,6 +74,29 @@ makeExclusionDistances(const t_atoms *a, gmx_atomprop_t aps,
     return exclusionDistances;
 }
 
+void readConformation(const char *confin, gmx_mtop_t *top,
+                      std::vector<RVec> *x, std::vector<RVec> *v,
+                      int *ePBC, matrix box, const char *statusTitle)
+{
+    fprintf(stderr, "Reading %s configuration%s\n", statusTitle,
+            v ? " and velocities" : "");
+    rvec                   *x_tmp = NULL, *v_tmp = NULL;
+    bool                    dummy;
+    readConfAndTopology(confin, &dummy, top, ePBC, x ? &x_tmp : NULL, v ? &v_tmp : NULL, box);
+    gmx::scoped_guard_sfree xguard(x_tmp);
+    gmx::scoped_guard_sfree vguard(v_tmp);
+    if (x && x_tmp)
+    {
+        *x = std::vector<RVec>(x_tmp, x_tmp + top->natoms);
+    }
+    if (v && v_tmp)
+    {
+        *v = std::vector<RVec>(v_tmp, v_tmp + top->natoms);
+    }
+    fprintf(stderr, "%s\nContaining %d atoms in %d residues\n",
+            *top->name, top->natoms, gmx_mtop_nres(top));
+}
+
 void readConformation(const char *confin, t_topology *top,
                       std::vector<RVec> *x, std::vector<RVec> *v,
                       int *ePBC, matrix box, const char *statusTitle)
index 984a126ae00b52a144760246bb5bc4e8a80160f9..63e0afcec2e8d4f5709bc32bc0e2c5c833f4c63d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -41,6 +41,7 @@
 #include "gromacs/utility/real.h"
 
 struct gmx_atomprop;
+struct gmx_mtop_t;
 struct t_atoms;
 struct t_topology;
 
@@ -54,6 +55,9 @@ std::vector<real>
 makeExclusionDistances(const t_atoms *a, gmx_atomprop *aps,
                        real defaultDistance, real scaleFactor);
 
+void readConformation(const char *confin, gmx_mtop_t *top,
+                      std::vector<gmx::RVec> *x, std::vector<gmx::RVec> *v,
+                      int *ePBC, matrix box, const char *statusTitle);
 /*! \brief Read a conformation from a file, allocate and fill data structures.
  *
  * Used by solvate and insert-molecules. The returned pointers *x and
index 054c0f648632621e8ff51bfbc2f1ffd3de6266d5..aac04e776aa14e5bef314811b63c446879462b32 100644 (file)
@@ -58,6 +58,8 @@
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/mdtypes/pull-params.h"
+#include "gromacs/options/options.h"
+#include "gromacs/options/treesupport.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/topology/block.h"
 #include "gromacs/topology/ifunc.h"
 #include "gromacs/topology/symtab.h"
 #include "gromacs/topology/topology.h"
 #include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/ikeyvaluetreeerror.h"
+#include "gromacs/utility/keyvaluetree.h"
+#include "gromacs/utility/keyvaluetreetransform.h"
 #include "gromacs/utility/smalloc.h"
+#include "gromacs/utility/stringcompare.h"
+#include "gromacs/utility/stringutil.h"
 
 #define MAXPTR 254
 #define NOGID  255
@@ -96,8 +105,6 @@ typedef struct t_inputrec_strings
     char   QMmethod[STRLEN], QMbasis[STRLEN], QMcharge[STRLEN], QMmult[STRLEN],
            bSH[STRLEN], CASorbitals[STRLEN], CASelectrons[STRLEN], SAon[STRLEN],
            SAoff[STRLEN], SAsteps[STRLEN], bTS[STRLEN], bOPT[STRLEN];
-    char efield_x[STRLEN], efield_xt[STRLEN], efield_y[STRLEN],
-         efield_yt[STRLEN], efield_z[STRLEN], efield_zt[STRLEN];
 
 } gmx_inputrec_strings;
 
@@ -1759,6 +1766,50 @@ static gmx_bool couple_lambda_has_vdw_on(int couple_lambda_value)
             couple_lambda_value == ecouplamVDWQ);
 }
 
+namespace
+{
+
+class MdpErrorHandler : public gmx::IKeyValueTreeErrorHandler
+{
+    public:
+        explicit MdpErrorHandler(warninp_t wi)
+            : wi_(wi), mapping_(nullptr)
+        {
+        }
+
+        void setBackMapping(const gmx::IKeyValueTreeBackMapping &mapping)
+        {
+            mapping_ = &mapping;
+        }
+
+        virtual bool onError(gmx::UserInputError *ex, const gmx::KeyValueTreePath &context)
+        {
+            ex->prependContext(gmx::formatString("Error in mdp option \"%s\":",
+                                                 getOptionName(context).c_str()));
+            std::string message = gmx::formatExceptionMessageToString(*ex);
+            warning_error(wi_, message.c_str());
+            return true;
+        }
+
+    private:
+        std::string getOptionName(const gmx::KeyValueTreePath &context)
+        {
+            if (mapping_ != nullptr)
+            {
+                gmx::KeyValueTreePath path = mapping_->originalPath(context);
+                GMX_ASSERT(path.size() == 1, "Inconsistent mapping back to mdp options");
+                return path[0];
+            }
+            GMX_ASSERT(context.size() == 1, "Inconsistent context for mdp option parsing");
+            return context[0];
+        }
+
+        warninp_t                            wi_;
+        const gmx::IKeyValueTreeBackMapping *mapping_;
+};
+
+} // namespace
+
 void get_ir(const char *mdparin, const char *mdparout,
             t_inputrec *ir, t_gromppopts *opts,
             warninp_t wi)
@@ -2187,18 +2238,26 @@ void get_ir(const char *mdparin, const char *mdparout,
     }
 
     /* Electric fields */
-    CCTYPE("Electric fields");
-    CTYPE ("Format is number of terms (int) and for all terms an amplitude (real)");
-    CTYPE ("and a phase angle (real)");
-    STYPE ("E-x",     is->efield_x,   NULL);
-    CTYPE ("Time dependent (pulsed) electric field. Format is omega, time for pulse");
-    CTYPE ("peak, and sigma (width) for pulse. Sigma = 0 removes pulse, leaving");
-    CTYPE ("the field to be a cosine function.");
-    STYPE ("E-xt",    is->efield_xt,  NULL);
-    STYPE ("E-y",     is->efield_y,   NULL);
-    STYPE ("E-yt",    is->efield_yt,  NULL);
-    STYPE ("E-z",     is->efield_z,   NULL);
-    STYPE ("E-zt",    is->efield_zt,  NULL);
+    {
+        gmx::KeyValueTreeObject      convertedValues = flatKeyValueTreeFromInpFile(ninp, inp);
+        gmx::KeyValueTreeTransformer transform;
+        transform.rules()->addRule()
+            .keyMatchType("/", gmx::StringCompareType::CaseAndDashInsensitive);
+        ir->efield->initMdpTransform(transform.rules());
+        for (const auto &path : transform.mappedPaths())
+        {
+            GMX_ASSERT(path.size() == 1, "Inconsistent mapping back to mdp options");
+            mark_einp_set(ninp, inp, path[0].c_str());
+        }
+        gmx::Options                 options;
+        ir->efield->initMdpOptions(&options);
+        MdpErrorHandler              errorHandler(wi);
+        auto                         result
+            = transform.transform(convertedValues, &errorHandler);
+        errorHandler.setBackMapping(result.backMapping());
+        gmx::assignOptionsFromKeyValueTree(&options, result.object(),
+                                           &errorHandler);
+    }
 
     /* Ion/water position swapping ("computational electrophysiology") */
     CCTYPE("Ion/water position swapping for computational electrophysiology setups");
@@ -2748,7 +2807,6 @@ static void calc_nrdf(gmx_mtop_t *mtop, t_inputrec *ir, char **gnames)
     double                 *nrdf_tc, *nrdf_vcm, nrdf_uc, *nrdf_vcm_sub;
     ivec                   *dof_vcm;
     gmx_mtop_atomloop_all_t aloop;
-    t_atom                 *atom;
     int                     mb, mol, ftype, as;
     gmx_molblock_t         *molb;
     gmx_moltype_t          *molt;
@@ -2789,6 +2847,7 @@ static void calc_nrdf(gmx_mtop_t *mtop, t_inputrec *ir, char **gnames)
 
     snew(nrdf2, natoms);
     aloop = gmx_mtop_atomloop_all_init(mtop);
+    const t_atom *atom;
     while (gmx_mtop_atomloop_all_next(aloop, &i, &atom))
     {
         nrdf2[i] = 0;
@@ -3023,54 +3082,6 @@ static void calc_nrdf(gmx_mtop_t *mtop, t_inputrec *ir, char **gnames)
     sfree(nrdf_vcm_sub);
 }
 
-static void decode_cos(char *s, t_cosines *cosine)
-{
-    char              *t;
-    char               format[STRLEN], f1[STRLEN];
-    double             a, phi;
-    int                i;
-
-    t = gmx_strdup(s);
-    trim(t);
-
-    cosine->n   = 0;
-    cosine->a   = NULL;
-    cosine->phi = NULL;
-    if (strlen(t))
-    {
-        if (sscanf(t, "%d", &(cosine->n)) != 1)
-        {
-            gmx_fatal(FARGS, "Cannot parse cosine multiplicity from string '%s'", t);
-        }
-        if (cosine->n <= 0)
-        {
-            cosine->n = 0;
-        }
-        else
-        {
-            snew(cosine->a, cosine->n);
-            snew(cosine->phi, cosine->n);
-
-            sprintf(format, "%%*d");
-            for (i = 0; (i < cosine->n); i++)
-            {
-                double  gmx_unused canary;
-
-                strcpy(f1, format);
-                strcat(f1, "%lf%lf%lf");
-                if (sscanf(t, f1, &a, &phi, &canary) != 2)
-                {
-                    gmx_fatal(FARGS, "Invalid input for electric field shift: '%s'", t);
-                }
-                cosine->a[i]   = a;
-                cosine->phi[i] = phi;
-                strcat(format, "%*lf%*lf");
-            }
-        }
-    }
-    sfree(t);
-}
-
 static gmx_bool do_egp_flag(t_inputrec *ir, gmx_groups_t *groups,
                             const char *option, const char *val, int flag)
 {
@@ -3789,13 +3800,6 @@ void do_index(const char* mdparin, const char *ndx,
         gmx_fatal(FARGS, "Can only have energy group pair tables in combination with user tables for VdW and/or Coulomb");
     }
 
-    decode_cos(is->efield_x, &(ir->ex[XX]));
-    decode_cos(is->efield_xt, &(ir->et[XX]));
-    decode_cos(is->efield_y, &(ir->ex[YY]));
-    decode_cos(is->efield_yt, &(ir->et[YY]));
-    decode_cos(is->efield_z, &(ir->ex[ZZ]));
-    decode_cos(is->efield_zt, &(ir->et[ZZ]));
-
     for (i = 0; (i < grps->nr); i++)
     {
         sfree(gnames[i]);
@@ -4075,7 +4079,6 @@ void triple_check(const char *mdparin, t_inputrec *ir, gmx_mtop_t *sys,
     rvec                      acc;
     gmx_mtop_atomloop_block_t aloopb;
     gmx_mtop_atomloop_all_t   aloop;
-    t_atom                   *atom;
     ivec                      AbsRef;
     char                      warn_buf[STRLEN];
 
@@ -4172,6 +4175,7 @@ void triple_check(const char *mdparin, t_inputrec *ir, gmx_mtop_t *sys,
 
     bCharge = FALSE;
     aloopb  = gmx_mtop_atomloop_block_init(sys);
+    const t_atom *atom;
     while (gmx_mtop_atomloop_block_next(aloopb, &atom, &nmol))
     {
         if (atom->q != 0 || atom->qB != 0)
@@ -4240,6 +4244,7 @@ void triple_check(const char *mdparin, t_inputrec *ir, gmx_mtop_t *sys,
         clear_rvec(acc);
         snew(mgrp, sys->groups.grps[egcACC].nr);
         aloop = gmx_mtop_atomloop_all_init(sys);
+        const t_atom *atom;
         while (gmx_mtop_atomloop_all_next(aloop, &i, &atom))
         {
             mgrp[ggrpnr(&sys->groups, egcACC, i)] += atom->m;
index e49696700de5adbd41065207a169289546fd78b2..f07e366586af67e97b5f19b58bd9e8ba9eef5c96 100644 (file)
@@ -514,7 +514,7 @@ pull_t *set_pull_init(t_inputrec *ir, const gmx_mtop_t *mtop,
     pull      = ir->pull;
     pull_work = init_pull(NULL, pull, ir, 0, NULL, mtop, NULL, oenv, lambda, FALSE, 0);
     md        = init_mdatoms(NULL, mtop, ir->efep);
-    atoms2md(mtop, ir, 0, NULL, mtop->natoms, md);
+    atoms2md(mtop, ir, -1, NULL, mtop->natoms, md);
     if (ir->efep)
     {
         update_mdatoms(md, lambda);
index 3e121c8078bbbf8c0cccbc72d7bcc652ad2f7f88..44dcc5f4b61e5fa61f190334af2c103aa5d1e791 100644 (file)
@@ -260,16 +260,6 @@ static void check_rtp(int nrtp, t_restp rtp[], char *libfn)
     }
 }
 
-static int comprtp(const void *a, const void *b)
-{
-    t_restp *ra, *rb;
-
-    ra = (t_restp *)a;
-    rb = (t_restp *)b;
-
-    return gmx_strcasecmp(ra->resname, rb->resname);
-}
-
 int get_bt(char* header)
 {
     int i;
@@ -551,7 +541,7 @@ void read_resall(char *rrdb, int *nrtpptr, t_restp **rtp,
     srenew(rrtp, nrtp);
 
     fprintf(stderr, "\nSorting it all out...\n");
-    qsort(rrtp, nrtp, (size_t)sizeof(rrtp[0]), comprtp);
+    std::sort(rrtp, rrtp+nrtp, [](const t_restp &a, const t_restp &b) {return gmx_strcasecmp(a.resname, b.resname) < 0; });
 
     check_rtp(nrtp, rrtp, rrdb);
 
index e37e6d3c31aa28afa7b37f598bea299527392c66..eca8837aecb2068f7b8da59fdd80688878f9a6c7 100644 (file)
@@ -65,6 +65,7 @@
 #include "gromacs/mdlib/genborn.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
+#include "gromacs/pbcutil/pbc.h"
 #include "gromacs/topology/block.h"
 #include "gromacs/topology/ifunc.h"
 #include "gromacs/topology/symtab.h"
@@ -73,6 +74,7 @@
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/futil.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/pleasecite.h"
 #include "gromacs/utility/smalloc.h"
 
 #define OPENDIR     '[' /* starting sign for directive */
@@ -581,7 +583,8 @@ static char **read_topol(const char *infile, const char *outfile,
                          gmx_bool        bFEP,
                          gmx_bool        bGenborn,
                          gmx_bool        bZero,
-                         warninp_t   wi)
+                         gmx_bool        usingFullRangeElectrostatics,
+                         warninp_t       wi)
 {
     FILE           *out;
     int             i, sl, nb_funct;
@@ -927,8 +930,13 @@ static char **read_topol(const char *infile, const char *outfile,
 
                             push_molt(symtab, &nmol, molinfo, pline, wi);
                             srenew(block2, nmol);
-                            block2[nmol-1].nr = 0;
-                            mi0               = &((*molinfo)[nmol-1]);
+                            block2[nmol-1].nr      = 0;
+                            mi0                    = &((*molinfo)[nmol-1]);
+                            mi0->atoms.haveMass    = TRUE;
+                            mi0->atoms.haveCharge  = TRUE;
+                            mi0->atoms.haveType    = TRUE;
+                            mi0->atoms.haveBState  = TRUE;
+                            mi0->atoms.havePdbInfo = FALSE;
                             break;
                         }
                         case d_atoms:
@@ -1086,6 +1094,7 @@ static char **read_topol(const char *infile, const char *outfile,
     {
         title = put_symtab(symtab, "");
     }
+
     if (fabs(qt) > 1e-4)
     {
         sprintf(warn_buf, "System has non-zero total charge: %.6f\n%s\n", qt, floating_point_arithmetic_tip);
@@ -1096,6 +1105,12 @@ static char **read_topol(const char *infile, const char *outfile,
         sprintf(warn_buf, "State B has non-zero total charge: %.6f\n%s\n", qBt, floating_point_arithmetic_tip);
         warning_note(wi, warn_buf);
     }
+    if (usingFullRangeElectrostatics && (fabs(qt) > 1e-4 || fabs(qBt) > 1e-4))
+    {
+        warning(wi, "You are using Ewald electrostatics in a system with net charge. This can lead to severe artifacts, such as ions moving into regions with low dielectric, due to the uniform background charge. We suggest to neutralize your system with counter ions, possibly in combination with a physiological salt concentration.");
+        please_cite(stdout, "Hub2014a");
+    }
+
     DS_Done (&DS);
     for (i = 0; i < nmol; i++)
     {
@@ -1160,7 +1175,9 @@ char **do_top(gmx_bool          bVerbose,
                        nrmols, molinfo, intermolecular_interactions,
                        plist, combination_rule, repulsion_power,
                        opts, fudgeQQ, nmolblock, molblock,
-                       ir->efep != efepNO, bGenborn, bZero, wi);
+                       ir->efep != efepNO, bGenborn, bZero,
+                       EEL_FULL(ir->coulombtype), wi);
+
     if ((*combination_rule != eCOMB_GEOMETRIC) &&
         (ir->vdwtype == evdwUSER))
     {
index 5a43f00963ba9a528252fd6f697788570574e014..8ac8938075045fe3aa3ebd1baae8c545eebf36b0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2012,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -85,18 +85,6 @@ int cu_copy_D2H_async(void * h_dest, void * d_src, size_t bytes, cudaStream_t s
     return cu_copy_D2H_generic(h_dest, d_src, bytes, true, s);
 }
 
-int cu_copy_D2H_alloc(void ** h_dest, void * d_src, size_t bytes)
-{
-    if (h_dest == NULL || d_src == NULL || bytes == 0)
-    {
-        return -1;
-    }
-
-    smalloc(*h_dest, bytes);
-
-    return cu_copy_D2H(*h_dest, d_src, bytes);
-}
-
 /*! Launches synchronous or asynchronous device to host memory copy.
  *
  *  The copy is launched in stream s or if not specified, in stream 0.
@@ -138,21 +126,6 @@ int cu_copy_H2D_async(void * d_dest, void * h_src, size_t bytes, cudaStream_t s
     return cu_copy_H2D_generic(d_dest, h_src, bytes, true, s);
 }
 
-int cu_copy_H2D_alloc(void ** d_dest, void * h_src, size_t bytes)
-{
-    cudaError_t stat;
-
-    if (d_dest == NULL || h_src == NULL || bytes == 0)
-    {
-        return -1;
-    }
-
-    stat = cudaMalloc(d_dest, bytes);
-    CU_RET_ERR(stat, "cudaMalloc failed in cu_copy_H2D_alloc");
-
-    return cu_copy_H2D(*d_dest, h_src, bytes);
-}
-
 float cu_event_elapsed(cudaEvent_t start, cudaEvent_t end)
 {
     float       t = 0.0;
index 5daa040d28f5e00e964766c351ed7af57917c991..1a99e1c904597b76a200c94156d86dc71f7f659d 100644 (file)
  * The CUDA device information is queried and set at detection and contains
  * both information about the device/hardware returned by the runtime as well
  * as additional data like support status.
+ *
+ * \todo extract an object to manage NVML details
  */
 struct gmx_device_info_t
 {
     int                 id;                      /* id of the CUDA device */
     cudaDeviceProp      prop;                    /* CUDA device properties */
     int                 stat;                    /* result of the device check */
-    gmx_bool            nvml_initialized;        /* If NVML was initialized */
     unsigned int        nvml_orig_app_sm_clock;  /* The original SM clock before we changed it */
     unsigned int        nvml_orig_app_mem_clock; /* The original memory clock before we changed it */
     gmx_bool            nvml_app_clocks_changed; /* If application clocks have been changed */
@@ -126,6 +127,7 @@ struct gmx_device_info_t
     unsigned int        nvml_set_app_mem_clock;  /* The memory clock we set */
 #if HAVE_NVML
     nvmlDevice_t        nvml_device_id;          /* NVML device id */
+    // TODO This can become a bool with a more useful name
     nvmlEnableState_t   nvml_is_restricted;      /* Status of application clocks permission */
 #endif                                           /* HAVE_NVML */
 };
@@ -137,9 +139,6 @@ int cu_copy_D2H(void * /*h_dest*/, void * /*d_src*/, size_t /*bytes*/);
 /*! Launches asynchronous host to device memory copy in stream s. */
 int cu_copy_D2H_async(void * /*h_dest*/, void * /*d_src*/, size_t /*bytes*/, cudaStream_t /*s = 0*/);
 
-/*! Allocates host memory and launches synchronous host to device memory copy. */
-int cu_copy_D2H_alloc(void ** /*h_dest*/, void * /*d_src*/, size_t /*bytes*/);
-
 
 /*! Launches synchronous host to device memory copy. */
 int cu_copy_H2D(void * /*d_dest*/, void * /*h_src*/, size_t /*bytes*/);
@@ -147,9 +146,6 @@ int cu_copy_H2D(void * /*d_dest*/, void * /*h_src*/, size_t /*bytes*/);
 /*! Launches asynchronous host to device memory copy in stream s. */
 int cu_copy_H2D_async(void * /*d_dest*/, void * /*h_src*/, size_t /*bytes*/, cudaStream_t /*s = 0*/);
 
-/*! Allocates device memory and launches synchronous host to device memory copy. */
-int cu_copy_H2D_alloc(void ** /*d_dest*/, void * /*h_src*/, size_t /*bytes*/);
-
 /*! Frees device memory and resets the size and allocation size to -1. */
 void cu_free_buffered(void *d_ptr, int *n = NULL, int *nalloc = NULL);
 
index e8b78249e909a45dcf6142ab1b3b83de3d1ff2c7..6e620cc144ca8bcfd9752ae7752e5c61bd8fcd1f 100644 (file)
@@ -55,6 +55,7 @@
 #include "gromacs/hardware/gpu_hw_info.h"
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/logger.h"
 #include "gromacs/utility/smalloc.h"
 
 #if HAVE_NVML
@@ -206,59 +207,6 @@ static int do_sanity_checks(int dev_id, cudaDeviceProp *dev_prop)
     return 0;
 }
 
-#if HAVE_NVML
-/* TODO: We should actually be using md_print_warn in md_logging.c,
- * but we can't include mpi.h in CUDA code.
- */
-static void md_print_info(FILE       *fplog,
-                          const char *fmt, ...)
-{
-    va_list ap;
-
-    if (fplog != NULL)
-    {
-        /* We should only print to stderr on the master node,
-         * in most cases fplog is only set on the master node, so this works.
-         */
-        va_start(ap, fmt);
-        vfprintf(stderr, fmt, ap);
-        va_end(ap);
-
-        va_start(ap, fmt);
-        vfprintf(fplog, fmt, ap);
-        va_end(ap);
-    }
-}
-#endif /*HAVE_NVML*/
-
-/* TODO: We should actually be using md_print_warn in md_logging.c,
- * but we can't include mpi.h in CUDA code.
- * This is replicated from nbnxn_cuda_data_mgmt.cu.
- */
-static void md_print_warn(FILE       *fplog,
-                          const char *fmt, ...)
-{
-    va_list ap;
-
-    if (fplog != NULL)
-    {
-        /* We should only print to stderr on the master node,
-         * in most cases fplog is only set on the master node, so this works.
-         */
-        va_start(ap, fmt);
-        fprintf(stderr, "\n");
-        vfprintf(stderr, fmt, ap);
-        fprintf(stderr, "\n");
-        va_end(ap);
-
-        va_start(ap, fmt);
-        fprintf(fplog, "\n");
-        vfprintf(fplog, fmt, ap);
-        fprintf(fplog, "\n");
-        va_end(ap);
-    }
-}
-
 #if HAVE_NVML_APPLICATION_CLOCKS
 /*! \brief Determines and adds the NVML device ID to the passed \cuda_dev.
  *
@@ -271,9 +219,9 @@ static void md_print_warn(FILE       *fplog,
 static bool addNVMLDeviceId(gmx_device_info_t* cuda_dev)
 {
     nvmlDevice_t nvml_device_id;
-    unsigned int nvml_device_count = 0;
-    nvmlReturn_t nvml_stat         = nvmlDeviceGetCount ( &nvml_device_count );
-    cuda_dev->nvml_initialized = false;
+    unsigned int nvml_device_count  = 0;
+    nvmlReturn_t nvml_stat          = nvmlDeviceGetCount ( &nvml_device_count );
+    bool         nvmlWasInitialized = false;
     HANDLE_NVML_RET_ERR( nvml_stat, "nvmlDeviceGetCount failed" );
     for (unsigned int nvml_device_idx = 0; nvml_stat == NVML_SUCCESS && nvml_device_idx < nvml_device_count; ++nvml_device_idx)
     {
@@ -295,12 +243,12 @@ static bool addNVMLDeviceId(gmx_device_info_t* cuda_dev)
             static_cast<unsigned int>(cuda_dev->prop.pciDeviceID) == nvml_pci_info.device &&
             static_cast<unsigned int>(cuda_dev->prop.pciDomainID) == nvml_pci_info.domain)
         {
-            cuda_dev->nvml_initialized = true;
+            nvmlWasInitialized         = true;
             cuda_dev->nvml_device_id   = nvml_device_id;
             break;
         }
     }
-    return cuda_dev->nvml_initialized;
+    return nvmlWasInitialized;
 }
 
 /*! \brief Reads and returns the application clocks for device.
@@ -337,12 +285,17 @@ static bool getApplicationClocks(const gmx_device_info_t *cuda_dev,
  * allow this. For future GPU architectures a more sophisticated scheme might be
  * required.
  *
- * \param[out] fplog        log file to write to
+ * \todo Refactor this into a detection phase and a work phase. Also
+ * refactor to remove compile-time dependence on logging header.
+ *
+ * \param     mdlog         log file to write to
  * \param[in] gpuid         index of the GPU to set application clocks for
  * \param[in] gpu_info      GPU info of all detected devices in the system.
  * \returns                 true if no error occurs during application clocks handling.
  */
-static gmx_bool init_gpu_application_clocks(FILE gmx_unused *fplog, int gmx_unused gpuid, const gmx_gpu_info_t gmx_unused *gpu_info)
+static gmx_bool init_gpu_application_clocks(
+        const gmx::MDLogger &mdlog, int gmx_unused gpuid,
+        const gmx_gpu_info_t gmx_unused *gpu_info)
 {
     const cudaDeviceProp *prop                        = &gpu_info->gpu_dev[gpuid].prop;
     int                   cuda_version_number         = prop->major * 10 + prop->minor;
@@ -354,26 +307,20 @@ static gmx_bool init_gpu_application_clocks(FILE gmx_unused *fplog, int gmx_unus
         return true;
     }
 #if !HAVE_NVML
-    int cuda_driver  = 0;
-    int cuda_runtime = 0;
-    cudaDriverGetVersion(&cuda_driver);
-    cudaRuntimeGetVersion(&cuda_runtime);
-    md_print_warn( fplog, "NOTE: GROMACS was configured without NVML support hence it can not exploit\n"
-                   "      application clocks of the detected %s GPU to improve performance.\n"
-                   "      Recompile with the NVML library (compatible with the driver used) or set application clocks manually.\n",
-                   prop->name);
+    GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+            "NOTE: GROMACS was configured without NVML support hence it can not exploit\n"
+            "      application clocks of the detected %s GPU to improve performance.\n"
+            "      Recompile with the NVML library (compatible with the driver used) or set application clocks manually.",
+            prop->name);
     return true;
 #else
     if (!bCompiledWithApplicationClockSupport)
     {
-        int cuda_driver  = 0;
-        int cuda_runtime = 0;
-        cudaDriverGetVersion(&cuda_driver);
-        cudaRuntimeGetVersion(&cuda_runtime);
-        md_print_warn( fplog, "NOTE: GROMACS was compiled with an old NVML library which does not support\n"
-                       "      managing application clocks of the detected %s GPU to improve performance.\n"
-                       "      If your GPU supports application clocks, upgrade NVML (and driver) and recompile or set the clocks manually.\n",
-                       prop->name );
+        GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                "NOTE: GROMACS was compiled with an old NVML library which does not support\n"
+                "      managing application clocks of the detected %s GPU to improve performance.\n"
+                "      If your GPU supports application clocks, upgrade NVML (and driver) and recompile or set the clocks manually.",
+                prop->name );
         return true;
     }
 
@@ -423,30 +370,43 @@ static gmx_bool init_gpu_application_clocks(FILE gmx_unused *fplog, int gmx_unus
     nvml_stat = nvmlDeviceGetAPIRestriction(cuda_dev->nvml_device_id, NVML_RESTRICTED_API_SET_APPLICATION_CLOCKS, &(cuda_dev->nvml_is_restricted));
     HANDLE_NVML_RET_ERR( nvml_stat, "nvmlDeviceGetAPIRestriction failed" );
 
-    /* Note: Distinguishing between different types of GPUs here might be necessary in the future,
-       e.g. if max application clocks should not be used for certain GPUs. */
-    if (nvml_stat == NVML_SUCCESS && cuda_dev->nvml_orig_app_sm_clock < max_sm_clock && cuda_dev->nvml_is_restricted == NVML_FEATURE_DISABLED)
-    {
-        md_print_info(fplog, "Changing GPU application clocks for %s to (%d,%d)\n", cuda_dev->prop.name, max_mem_clock, max_sm_clock);
-        nvml_stat = nvmlDeviceSetApplicationsClocks(cuda_dev->nvml_device_id, max_mem_clock, max_sm_clock);
-        HANDLE_NVML_RET_ERR( nvml_stat, "nvmlDeviceGetApplicationsClock failed" );
-        cuda_dev->nvml_app_clocks_changed = true;
-        cuda_dev->nvml_set_app_sm_clock   = max_sm_clock;
-        cuda_dev->nvml_set_app_mem_clock  = max_mem_clock;
-    }
-    else if (nvml_stat == NVML_SUCCESS && cuda_dev->nvml_orig_app_sm_clock < max_sm_clock)
+    if (nvml_stat != NVML_SUCCESS)
     {
-        md_print_warn(fplog, "Can not change application clocks for %s to optimal values due to insufficient permissions. Current values are (%d,%d), max values are (%d,%d).\nUse sudo nvidia-smi -acp UNRESTRICTED or contact your admin to change application clocks.\n", cuda_dev->prop.name, cuda_dev->nvml_orig_app_mem_clock, cuda_dev->nvml_orig_app_sm_clock, max_mem_clock, max_sm_clock);
+        GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                "Can not change GPU application clocks to optimal values due to NVML error (%d): %s.",
+                nvml_stat, nvmlErrorString(nvml_stat));
+        return false;
     }
-    else if (nvml_stat == NVML_SUCCESS && cuda_dev->nvml_orig_app_sm_clock == max_sm_clock)
+
+    if (cuda_dev->nvml_is_restricted != NVML_FEATURE_DISABLED)
     {
-        md_print_info(fplog, "Application clocks (GPU clocks) for %s are (%d,%d)\n", cuda_dev->prop.name, cuda_dev->nvml_orig_app_mem_clock, cuda_dev->nvml_orig_app_sm_clock);
+        GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                "Cannot change application clocks for %s to optimal values due to insufficient permissions. Current values are (%d,%d), max values are (%d,%d).\nUse sudo nvidia-smi -acp UNRESTRICTED or contact your admin to change application clocks.",
+                cuda_dev->prop.name, cuda_dev->nvml_orig_app_mem_clock, cuda_dev->nvml_orig_app_sm_clock, max_mem_clock, max_sm_clock);
+        return true;
     }
-    else
+
+    if (cuda_dev->nvml_orig_app_sm_clock >= max_sm_clock)
     {
-        md_print_warn( fplog,  "Can not change GPU application clocks to optimal values due to NVML error (%d): %s.\n", nvml_stat, nvmlErrorString(nvml_stat));
+        //TODO: This should probably be integrated into the GPU Properties table.
+        GMX_LOG(mdlog.warning).appendTextFormatted(
+                "Application clocks (GPU clocks) for %s are (%d,%d)",
+                cuda_dev->prop.name, cuda_dev->nvml_orig_app_mem_clock, cuda_dev->nvml_orig_app_sm_clock);
+        return true;
     }
-    return (nvml_stat == NVML_SUCCESS);
+
+    /* Note: Distinguishing between different types of GPUs here might be necessary in the future,
+       e.g. if max application clocks should not be used for certain GPUs. */
+    GMX_LOG(mdlog.warning).appendTextFormatted(
+            "Changing GPU application clocks for %s to (%d,%d)",
+            cuda_dev->prop.name, max_mem_clock, max_sm_clock);
+    nvml_stat = nvmlDeviceSetApplicationsClocks(cuda_dev->nvml_device_id, max_mem_clock, max_sm_clock);
+    HANDLE_NVML_RET_ERR( nvml_stat, "nvmlDeviceGetApplicationsClock failed" );
+    cuda_dev->nvml_app_clocks_changed = true;
+    cuda_dev->nvml_set_app_sm_clock   = max_sm_clock;
+    cuda_dev->nvml_set_app_mem_clock  = max_mem_clock;
+
+    return true;
 #endif /* HAVE_NVML */
 }
 
@@ -484,7 +444,7 @@ static gmx_bool reset_gpu_application_clocks(const gmx_device_info_t gmx_unused
 #endif /* HAVE_NVML_APPLICATION_CLOCKS */
 }
 
-gmx_bool init_gpu(FILE gmx_unused *fplog, int mygpu, char *result_str,
+gmx_bool init_gpu(const gmx::MDLogger &mdlog, int mygpu, char *result_str,
                   const struct gmx_gpu_info_t *gpu_info,
                   const struct gmx_gpu_opt_t *gpu_opt)
 {
@@ -497,7 +457,7 @@ gmx_bool init_gpu(FILE gmx_unused *fplog, int mygpu, char *result_str,
 
     if (mygpu < 0 || mygpu >= gpu_opt->n_dev_use)
     {
-        sprintf(sbuf, "Trying to initialize an inexistent GPU: "
+        sprintf(sbuf, "Trying to initialize an non-existent GPU: "
                 "there are %d %s-selected GPU(s), but #%d was requested.",
                 gpu_opt->n_dev_use, gpu_opt->bUserSet ? "user" : "auto", mygpu);
         gmx_incons(sbuf);
@@ -516,7 +476,7 @@ gmx_bool init_gpu(FILE gmx_unused *fplog, int mygpu, char *result_str,
     //Ignoring return value as NVML errors should be treated not critical.
     if (stat == cudaSuccess)
     {
-        init_gpu_application_clocks(fplog, gpuid, gpu_info);
+        init_gpu_application_clocks(mdlog, gpuid, gpu_info);
     }
     return (stat == cudaSuccess);
 }
index f485abb0fb4f1ff8b7b7661ff8c713180ab3919f..b99c57159730e13e293e89e00659cc0d232aabb1 100644 (file)
 struct gmx_gpu_info_t;
 struct gmx_gpu_opt_t;
 
+namespace gmx
+{
+class MDLogger;
+}
+
 /*! \brief Detect all GPUs in the system.
  *
  *  Will detect every GPU supported by the device driver in use. Also
@@ -115,7 +120,7 @@ void free_gpu_info(const struct gmx_gpu_info_t *GPU_FUNC_ARGUMENT(gpu_info)) GPU
  * The varible \p mygpu is the index of the GPU to initialize in the
  * gpu_info.gpu_dev array.
  *
- * \param[out] fplog        log file to write to
+ * \param      mdlog        log file to write to
  * \param[in]  mygpu        index of the GPU to initialize
  * \param[out] result_str   the message related to the error that occurred
  *                          during the initialization (if there was any).
@@ -124,7 +129,7 @@ void free_gpu_info(const struct gmx_gpu_info_t *GPU_FUNC_ARGUMENT(gpu_info)) GPU
  * \returns                 true if no error occurs during initialization.
  */
 GPU_FUNC_QUALIFIER
-gmx_bool init_gpu(FILE *GPU_FUNC_ARGUMENT(fplog),
+gmx_bool init_gpu(const gmx::MDLogger &GPU_FUNC_ARGUMENT(mdlog),
                   int GPU_FUNC_ARGUMENT(mygpu),
                   char *GPU_FUNC_ARGUMENT(result_str),
                   const struct gmx_gpu_info_t *GPU_FUNC_ARGUMENT(gpu_info),
index 3a41f41bb976d10597d5dd6e340538ee3662a5e9..a03839217d5ae4c9439bb362432d92846b6ce9ba 100644 (file)
@@ -447,7 +447,7 @@ void get_gpu_device_info_string(char gmx_unused *s, const gmx_gpu_info_t gmx_unu
 }
 
 //! This function is documented in the header file
-gmx_bool init_gpu(FILE gmx_unused                 *fplog,
+gmx_bool init_gpu(const gmx::MDLogger              & /*mdlog*/,
                   int                              mygpu,
                   char                            *result_str,
                   const gmx_gpu_info_t gmx_unused *gpu_info,
@@ -461,7 +461,7 @@ gmx_bool init_gpu(FILE gmx_unused                 *fplog,
     if (mygpu < 0 || mygpu >= gpu_opt->n_dev_use)
     {
         char        sbuf[STRLEN];
-        sprintf(sbuf, "Trying to initialize an inexistent GPU: "
+        sprintf(sbuf, "Trying to initialize an non-existent GPU: "
                 "there are %d %s-selected GPU(s), but #%d was requested.",
                 gpu_opt->n_dev_use, gpu_opt->bUserSet ? "user" : "auto", mygpu);
         gmx_incons(sbuf);
index 77a50db495d3ff9460fe99611b9eb77fc1099b6e..116b24fe71f4a56823d27fbf4915e8306d5af48c 100644 (file)
@@ -57,6 +57,13 @@ endif()
 include(${_gmx_import_file})
 unset(_gmx_import_file)
 
+get_target_property(_libs libgromacs INTERFACE_LINK_LIBRARIES)
+if (_libs MATCHES "tng_io::tng_io")
+    include(CMakeFindDependencyMacro)
+    find_dependency(TNG_IO)
+endif()
+unset(_libs)
+
 set(GROMACS_INCLUDE_DIRS)
 set(_include_dirs "@INSTALLED_HEADER_INCLUDE_DIRS@")
 foreach (_dir ${_include_dirs})
index 83016454f57456d86461bfafa2a7f16bdad8059b..cc8d1e7594c3aefe931e0a1623ed9341408da09a 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2015, by the GROMACS development team, led by
+# Copyright (c) 2015,2016, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -35,6 +35,7 @@
 gmx_add_libgromacs_sources(
     cpuinfo.cpp
     detecthardware.cpp
+    hardwareassign.cpp
     hardwaretopology.cpp
     )
 
index 5dccfa37d4865738f4306f6dbc7bc467c9f47067..5a17e09256ee0c255d888168ec6f833ef4c6244f 100644 (file)
@@ -50,7 +50,6 @@
 
 #include "thread_mpi/threads.h"
 
-#include "gromacs/gmxlib/md_logging.h"
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/gpu_utils/gpu_utils.h"
 #include "gromacs/hardware/cpuinfo.h"
@@ -68,6 +67,7 @@
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/logger.h"
 #include "gromacs/utility/programcontext.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/stringutil.h"
@@ -140,7 +140,6 @@ static tMPI_Thread_mutex_t hw_info_lock = TMPI_THREAD_MUTEX_INITIALIZER;
 #define HOSTNAMELEN 80
 
 /* FW decl. */
-static void set_gpu_ids(gmx_gpu_opt_t *gpu_opt, int nrank, int rank);
 static int gmx_count_gpu_dev_unique(const gmx_gpu_info_t *gpu_info,
                                     const gmx_gpu_opt_t  *gpu_opt);
 
@@ -154,60 +153,16 @@ gmx_bool gmx_gpu_sharing_supported()
     return bGpuSharingSupported;
 }
 
-static void sprint_gpus(char *sbuf, const gmx_gpu_info_t *gpu_info)
+std::string sprint_gpus(const gmx_gpu_info_t *gpu_info)
 {
-    int      i, ndev;
-    char     stmp[STRLEN];
-
-    ndev = gpu_info->n_dev;
-
-    sbuf[0] = '\0';
-    for (i = 0; i < ndev; i++)
+    char                     stmp[STRLEN];
+    std::vector<std::string> gpuStrings;
+    for (int i = 0; i < gpu_info->n_dev; i++)
     {
         get_gpu_device_info_string(stmp, gpu_info, i);
-        strcat(sbuf, "    ");
-        strcat(sbuf, stmp);
-        if (i < ndev - 1)
-        {
-            strcat(sbuf, "\n");
-        }
-    }
-}
-
-static void print_gpu_detection_stats(FILE                 *fplog,
-                                      const gmx_gpu_info_t *gpu_info,
-                                      const t_commrec      *cr)
-{
-    char onhost[HOSTNAMELEN+10], stmp[STRLEN];
-    int  ngpu;
-
-    if (!gpu_info->bDetectGPUs)
-    {
-        /* We skipped the detection, so don't print detection stats */
-        return;
-    }
-
-    ngpu = gpu_info->n_dev;
-
-#if GMX_LIB_MPI
-    /* We only print the detection on one, of possibly multiple, nodes */
-    std::strncpy(onhost, " on host ", 10);
-    gmx_gethostname(onhost + 9, HOSTNAMELEN);
-#else
-    /* We detect all relevant GPUs */
-    std::strncpy(onhost, "", 1);
-#endif
-
-    if (ngpu > 0)
-    {
-        sprint_gpus(stmp, gpu_info);
-        md_print_warn(cr, fplog, "%d GPU%s detected%s:\n%s\n",
-                      ngpu, (ngpu > 1) ? "s" : "", onhost, stmp);
-    }
-    else
-    {
-        md_print_warn(cr, fplog, "No GPUs detected%s\n", onhost);
+        gpuStrings.push_back(gmx::formatString("    %s", stmp));
     }
+    return gmx::joinStrings(gpuStrings, "\n");
 }
 
 /*! \brief Helper function for reporting GPU usage information
@@ -295,8 +250,7 @@ makeGpuUsageReport(const gmx_gpu_info_t *gpu_info,
 /* Give a suitable fatal error or warning if the build configuration
    and runtime CPU do not match. */
 static void
-check_use_of_rdtscp_on_this_cpu(FILE                  *fplog,
-                                const t_commrec       *cr,
+check_use_of_rdtscp_on_this_cpu(const gmx::MDLogger   &mdlog,
                                 const gmx::CpuInfo    &cpuInfo)
 {
 #ifdef HAVE_RDTSCP
@@ -311,10 +265,11 @@ check_use_of_rdtscp_on_this_cpu(FILE                  *fplog,
     {
         if (binaryUsesRdtscp)
         {
-            md_print_warn(cr, fplog, "The %s executable was compiled to use the rdtscp CPU instruction. "
-                          "We cannot detect the features of your current CPU, but will proceed anyway. "
-                          "If you get a crash, rebuild GROMACS with the GMX_USE_RDTSCP=OFF CMake option.",
-                          programName);
+            GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                    "The %s executable was compiled to use the rdtscp CPU instruction. "
+                    "We cannot detect the features of your current CPU, but will proceed anyway. "
+                    "If you get a crash, rebuild GROMACS with the GMX_USE_RDTSCP=OFF CMake option.",
+                    programName);
         }
     }
     else
@@ -331,16 +286,17 @@ check_use_of_rdtscp_on_this_cpu(FILE                  *fplog,
 
         if (cpuHasRdtscp && !binaryUsesRdtscp)
         {
-            md_print_warn(cr, fplog, "The current CPU can measure timings more accurately than the code in\n"
-                          "%s was configured to use. This might affect your simulation\n"
-                          "speed as accurate timings are needed for load-balancing.\n"
-                          "Please consider rebuilding %s with the GMX_USE_RDTSCP=ON CMake option.\n",
-                          programName, programName);
+            GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                    "The current CPU can measure timings more accurately than the code in\n"
+                    "%s was configured to use. This might affect your simulation\n"
+                    "speed as accurate timings are needed for load-balancing.\n"
+                    "Please consider rebuilding %s with the GMX_USE_RDTSCP=ON CMake option.",
+                    programName, programName);
         }
     }
 }
 
-void gmx_check_hw_runconf_consistency(FILE                *fplog,
+void gmx_check_hw_runconf_consistency(const gmx::MDLogger &mdlog,
                                       const gmx_hw_info_t *hwinfo,
                                       const t_commrec     *cr,
                                       const gmx_hw_opt_t  *hw_opt,
@@ -382,18 +338,18 @@ void gmx_check_hw_runconf_consistency(FILE                *fplog,
 
     if (hwinfo->gpu_info.n_dev_compatible > 0)
     {
-        std::string gpuUseageReport;
+        std::string gpuUsageReport;
         try
         {
-            gpuUseageReport = makeGpuUsageReport(&hwinfo->gpu_info,
-                                                 &hw_opt->gpu_opt,
-                                                 cr->nrank_pp_intranode,
-                                                 bMPI && cr->nnodes > 1);
+            gpuUsageReport = makeGpuUsageReport(&hwinfo->gpu_info,
+                                                &hw_opt->gpu_opt,
+                                                cr->nrank_pp_intranode,
+                                                bMPI && cr->nnodes > 1);
         }
         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
 
         /* NOTE: this print is only for and on one physical node */
-        md_print_info(cr, fplog, "%s\n", gpuUseageReport.c_str());
+        GMX_LOG(mdlog.warning).appendText(gpuUsageReport);
     }
 
     /* Need to ensure that we have enough GPUs:
@@ -461,13 +417,13 @@ void gmx_check_hw_runconf_consistency(FILE                *fplog,
             {
                 /* There are more GPUs than tMPI threads; we have
                    limited the number GPUs used. */
-                md_print_warn(cr, fplog,
-                              "NOTE: %d GPU%s were detected, but only %d PP thread-MPI thread%s can be started.\n"
-                              "      %s can use one GPU per PP tread-MPI thread, so only %d GPU%s will be used.\n",
-                              ngpu_comp, gpu_comp_plural,
-                              npppn, th_or_proc_plural,
-                              programName, npppn,
-                              npppn > 1 ? "s" : "");
+                GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                        "NOTE: %d GPU%s were detected, but only %d PP thread-MPI thread%s can be started.\n"
+                        "      %s can use one GPU per PP tread-MPI thread, so only %d GPU%s will be used.",
+                        ngpu_comp, gpu_comp_plural,
+                        npppn, th_or_proc_plural,
+                        programName, npppn,
+                        npppn > 1 ? "s" : "");
             }
         }
 
@@ -489,13 +445,13 @@ void gmx_check_hw_runconf_consistency(FILE                *fplog,
             /* TODO Should we have a gpu_opt->n_dev_supported field? */
             if (ngpu_comp > npppn && gmx_multiple_gpu_per_node_supported())
             {
-                md_print_warn(cr, fplog,
-                              "NOTE: potentially sub-optimal launch configuration, %s started with less\n"
-                              "      PP %s%s%s than GPU%s available.\n"
-                              "      Each PP %s can use only one GPU, %d GPU%s%s will be used.\n",
-                              programName, th_or_proc,
-                              th_or_proc_plural, pernode, gpu_comp_plural,
-                              th_or_proc, npppn, gpu_use_plural, pernode);
+                GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                        "NOTE: potentially sub-optimal launch configuration, %s started with less\n"
+                        "      PP %s%s%s than GPU%s available.\n"
+                        "      Each PP %s can use only one GPU, %d GPU%s%s will be used.",
+                        programName, th_or_proc,
+                        th_or_proc_plural, pernode, gpu_comp_plural,
+                        th_or_proc, npppn, gpu_use_plural, pernode);
             }
 
             if (ngpu_use != npppn)
@@ -538,9 +494,9 @@ void gmx_check_hw_runconf_consistency(FILE                *fplog,
 
             if (same_count > 0)
             {
-                md_print_info(cr, fplog,
-                              "NOTE: You assigned %s to multiple %s%s.\n",
-                              same_count > 1 ? "GPUs" : "a GPU", th_or_proc, btMPI ? "s" : "es");
+                GMX_LOG(mdlog.warning).appendTextFormatted(
+                        "NOTE: You assigned %s to multiple %s%s.",
+                        same_count > 1 ? "GPUs" : "a GPU", th_or_proc, btMPI ? "s" : "es");
             }
         }
     }
@@ -626,7 +582,7 @@ static int gmx_count_gpu_dev_unique(const gmx_gpu_info_t *gpu_info,
     return uniq_count;
 }
 
-static void gmx_detect_gpus(FILE *fplog, const t_commrec *cr)
+static void gmx_detect_gpus(const gmx::MDLogger &mdlog, const t_commrec *cr)
 {
 #if GMX_LIB_MPI
     int              rank_world;
@@ -654,6 +610,7 @@ static void gmx_detect_gpus(FILE *fplog, const t_commrec *cr)
     MPI_Comm_split(MPI_COMM_WORLD, gmx_physicalnode_id_hash(),
                    rank_world, &physicalnode_comm);
     MPI_Comm_rank(physicalnode_comm, &rank_local);
+    GMX_UNUSED_VALUE(cr);
 #else
     /* Here there should be only one process, check this */
     GMX_RELEASE_ASSERT(cr->nnodes == 1 && cr->sim_nodeid == 0, "Only a single (master) process should execute here");
@@ -679,10 +636,10 @@ static void gmx_detect_gpus(FILE *fplog, const t_commrec *cr)
             {
                 sprintf(sbuf, ".");
             }
-            md_print_warn(cr, fplog,
-                          "NOTE: Error occurred during GPU detection%s"
-                          "      Can not use GPU acceleration, will fall back to CPU kernels.\n",
-                          sbuf);
+            GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                    "NOTE: Error occurred during GPU detection%s"
+                    "      Can not use GPU acceleration, will fall back to CPU kernels.",
+                    sbuf);
         }
     }
 
@@ -857,14 +814,12 @@ static void
 spinUpCore() noexcept
 {
 #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_CONF) && defined(_SC_NPROCESSORS_ONLN)
-    // steady_clock is better than system_clock, but unsupported in gcc-4.6.4.
-    // For release-2017 we can retire gcc-4.6 support and move to steady_clock.
     float dummy           = 0.1;
     int   countConfigured = sysconf(_SC_NPROCESSORS_CONF);    // noexcept
-    auto  start           = std::chrono::system_clock::now(); // noexcept
+    auto  start           = std::chrono::steady_clock::now(); // noexcept
 
     while (sysconf(_SC_NPROCESSORS_ONLN) < countConfigured &&
-           std::chrono::system_clock::now() - start < std::chrono::seconds(2))
+           std::chrono::steady_clock::now() - start < std::chrono::seconds(2))
     {
         for (int i = 1; i < 10000; i++)
         {
@@ -924,19 +879,17 @@ hardwareTopologyPrepareDetection()
 #endif
 }
 
-/*! \brief Sanity check hardware topology and optionally print some notes to log
+/*! \brief Sanity check hardware topology and print some notes to log
  *
- *  \param fplog            Log file pointer. This can be NULL, but the then routine
- *                          will not do anything.
+ *  \param mdlog            Logger.
  *  \param hardwareTopology Reference to hardwareTopology object.
  */
 static void
-hardwareTopologyDoubleCheckDetection(FILE gmx_unused                          *fplog,
-                                     const gmx::HardwareTopology gmx_unused   &hardwareTopology)
+hardwareTopologyDoubleCheckDetection(const gmx::MDLogger gmx_unused         &mdlog,
+                                     const gmx::HardwareTopology gmx_unused &hardwareTopology)
 {
 #if defined HAVE_SYSCONF && defined(_SC_NPROCESSORS_CONF)
-    if (fplog == NULL ||
-        hardwareTopology.supportLevel() < gmx::HardwareTopology::SupportLevel::LogicalProcessorCount)
+    if (hardwareTopology.supportLevel() < gmx::HardwareTopology::SupportLevel::LogicalProcessorCount)
     {
         return;
     }
@@ -951,24 +904,27 @@ hardwareTopologyDoubleCheckDetection(FILE gmx_unused                          *f
      */
     if (countConfigured >= 0 && countConfigured != countFromDetection)
     {
-        fprintf(fplog, "Note: %d CPUs configured, but only %d were detected to be online.\n", countConfigured, countFromDetection);
+        GMX_LOG(mdlog.info).
+            appendTextFormatted("Note: %d CPUs configured, but only %d were detected to be online.\n", countConfigured, countFromDetection);
 
         if (isX86 && countConfigured == 2*countFromDetection)
         {
-            fprintf(fplog, "      X86 Hyperthreading is likely disabled; enable it for better performance.\n");
+            GMX_LOG(mdlog.info).
+                appendText("      X86 Hyperthreading is likely disabled; enable it for better performance.");
         }
         // For PowerPC (likely Power8) it is possible to set SMT to either 2,4, or 8-way hardware threads.
         // We only warn if it is completely disabled since default performance drops with SMT8.
         if (isPowerPC && countConfigured == 8*countFromDetection)
         {
-            fprintf(fplog, "      PowerPC SMT is likely disabled; enable SMT2/SMT4 for better performance.\n");
+            GMX_LOG(mdlog.info).
+                appendText("      PowerPC SMT is likely disabled; enable SMT2/SMT4 for better performance.");
         }
     }
 #endif
 }
 
 
-gmx_hw_info_t *gmx_detect_hardware(FILE *fplog, const t_commrec *cr,
+gmx_hw_info_t *gmx_detect_hardware(const gmx::MDLogger &mdlog, const t_commrec *cr,
                                    gmx_bool bDetectGPUs)
 {
     int ret;
@@ -993,7 +949,7 @@ gmx_hw_info_t *gmx_detect_hardware(FILE *fplog, const t_commrec *cr,
         // If we detected the topology on this system, double-check that it makes sense
         if (hwinfo_g->hardwareTopology->isThisSystem())
         {
-            hardwareTopologyDoubleCheckDetection(fplog, *(hwinfo_g->hardwareTopology));
+            hardwareTopologyDoubleCheckDetection(mdlog, *(hwinfo_g->hardwareTopology));
         }
 
         // TODO: Get rid of this altogether.
@@ -1012,7 +968,7 @@ gmx_hw_info_t *gmx_detect_hardware(FILE *fplog, const t_commrec *cr,
              getenv("GMX_DISABLE_GPU_DETECTION") == NULL);
         if (hwinfo_g->gpu_info.bDetectGPUs)
         {
-            gmx_detect_gpus(fplog, cr);
+            gmx_detect_gpus(mdlog, cr);
         }
 
         gmx_collect_hardware_mpi(*hwinfo_g->cpuInfo);
@@ -1252,16 +1208,14 @@ static std::string detected_hardware_string(const gmx_hw_info_t *hwinfo,
                                hwinfo->gpu_info.n_dev);
         if (hwinfo->gpu_info.n_dev > 0)
         {
-            char buf[STRLEN];
-
-            sprint_gpus(buf, &hwinfo->gpu_info);
-            s += gmx::formatString("%s\n", buf);
+            s += sprint_gpus(&hwinfo->gpu_info) + "\n";
         }
     }
     return s;
 }
 
 void gmx_print_detected_hardware(FILE *fplog, const t_commrec *cr,
+                                 const gmx::MDLogger &mdlog,
                                  const gmx_hw_info_t *hwinfo)
 {
     const gmx::CpuInfo &cpuInfo = *hwinfo_g->cpuInfo;
@@ -1293,7 +1247,7 @@ void gmx_print_detected_hardware(FILE *fplog, const t_commrec *cr,
     }
 
     /* For RDTSCP we only check on our local node and skip the MPI reduction */
-    check_use_of_rdtscp_on_this_cpu(fplog, cr, cpuInfo);
+    check_use_of_rdtscp_on_this_cpu(mdlog, cpuInfo);
 }
 
 //! \brief Return if any GPU ID (e.g in a user-supplied string) is repeated
@@ -1363,132 +1317,6 @@ void gmx_parse_gpu_ids(gmx_gpu_opt_t *gpu_opt)
     }
 }
 
-void gmx_select_gpu_ids(FILE *fplog, const t_commrec *cr,
-                        const gmx_gpu_info_t *gpu_info,
-                        gmx_bool bForceUseGPU,
-                        gmx_gpu_opt_t *gpu_opt)
-{
-    int              i;
-    char             sbuf[STRLEN], stmp[STRLEN];
-
-    /* Bail if binary is not compiled with GPU acceleration, but this is either
-     * explicitly (-nb gpu) or implicitly (gpu ID passed) requested. */
-    if (bForceUseGPU && !bGPUBinary)
-    {
-        gmx_fatal(FARGS, "GPU acceleration requested, but %s was compiled without GPU support!",
-                  gmx::getProgramContext().displayName());
-    }
-
-    if (!(cr->duty & DUTY_PP))
-    {
-        /* Our rank is not doing PP, we don't use a GPU */
-        return;
-    }
-
-    if (gpu_opt->bUserSet)
-    {
-        /* Check the GPU IDs passed by the user.
-         * (GPU IDs have been parsed by gmx_parse_gpu_ids before)
-         */
-        int *checkres;
-        int  res;
-
-        snew(checkres, gpu_opt->n_dev_use);
-
-        res = check_selected_gpus(checkres, gpu_info, gpu_opt);
-
-        if (!res)
-        {
-            print_gpu_detection_stats(fplog, gpu_info, cr);
-
-            sprintf(sbuf, "Some of the requested GPUs do not exist, behave strangely, or are not compatible:\n");
-            for (i = 0; i < gpu_opt->n_dev_use; i++)
-            {
-                if (checkres[i] != egpuCompatible)
-                {
-                    sprintf(stmp, "    GPU #%d: %s\n",
-                            gpu_opt->dev_use[i],
-                            gpu_detect_res_str[checkres[i]]);
-                    strcat(sbuf, stmp);
-                }
-            }
-            gmx_fatal(FARGS, "%s", sbuf);
-        }
-
-        sfree(checkres);
-    }
-    else if (getenv("GMX_EMULATE_GPU") == NULL)
-    {
-        pick_compatible_gpus(&hwinfo_g->gpu_info, gpu_opt);
-        set_gpu_ids(gpu_opt, cr->nrank_pp_intranode, cr->rank_pp_intranode);
-    }
-
-    /* If the user asked for a GPU, check whether we have a GPU */
-    if (bForceUseGPU && gpu_info->n_dev_compatible == 0)
-    {
-        gmx_fatal(FARGS, "GPU acceleration requested, but no compatible GPUs were detected.");
-    }
-}
-
-/* Select the GPUs we will use. This is an operation local to each physical
- * node. If we have less MPI ranks than GPUs, we will waste some GPUs.
- * nrank and rank are the rank count and id for PP processes in our node.
- */
-static void set_gpu_ids(gmx_gpu_opt_t *gpu_opt, int nrank, int rank)
-{
-    GMX_RELEASE_ASSERT(gpu_opt, "Invalid gpu_opt pointer passed");
-    GMX_RELEASE_ASSERT(nrank >= 1,
-                       gmx::formatString("Invalid limit (%d) for the number of GPUs (detected %d compatible GPUs)",
-                                         rank, gpu_opt->n_dev_compatible).c_str());
-
-    if (gpu_opt->n_dev_compatible == 0)
-    {
-        char host[HOSTNAMELEN];
-
-        gmx_gethostname(host, HOSTNAMELEN);
-        gmx_fatal(FARGS, "A GPU was requested on host %s, but no compatible GPUs were detected. All nodes with PP ranks need to have GPUs. If you intended to use GPU acceleration in a parallel run, you can either avoid using the nodes that don't have GPUs or place PME ranks on these nodes.", host);
-    }
-
-    int nshare;
-
-    nshare = 1;
-    if (nrank > gpu_opt->n_dev_compatible)
-    {
-        if (nrank % gpu_opt->n_dev_compatible == 0)
-        {
-            nshare = gmx_gpu_sharing_supported() ? nrank/gpu_opt->n_dev_compatible : 1;
-        }
-        else
-        {
-            if (rank == 0)
-            {
-                gmx_fatal(FARGS, "The number of MPI ranks (%d) in a physical node is not a multiple of the number of GPUs (%d). Select a different number of MPI ranks or use the -gpu_id option to manually specify the GPU to be used.",
-                          nrank, gpu_opt->n_dev_compatible);
-            }
-
-#if GMX_MPI
-            /* We use a global barrier to prevent ranks from continuing with
-             * an invalid setup.
-             */
-            MPI_Barrier(MPI_COMM_WORLD);
-#endif
-        }
-    }
-
-    /* Here we will waste GPUs when nrank < gpu_opt->n_dev_compatible */
-    gpu_opt->n_dev_use = std::min(gpu_opt->n_dev_compatible*nshare, nrank);
-    if (!gmx_multiple_gpu_per_node_supported())
-    {
-        gpu_opt->n_dev_use = std::min(gpu_opt->n_dev_use, 1);
-    }
-    snew(gpu_opt->dev_use, gpu_opt->n_dev_use);
-    for (int i = 0; i != gpu_opt->n_dev_use; ++i)
-    {
-        /* TODO: improve this implementation: either sort GPUs or remove the weakest here */
-        gpu_opt->dev_use[i] = gpu_opt->dev_compatible[i/nshare];
-    }
-}
-
 void gmx_hardware_info_free(gmx_hw_info_t *hwinfo)
 {
     int ret;
index e002d47d16e3bee26e21863002e9617232e05c13..eff5c9623d4c81d84d0566a60430145867963511 100644 (file)
@@ -37,6 +37,8 @@
 
 #include <cstdio>
 
+#include <string>
+
 #include "gromacs/utility/basedefinitions.h"
 
 struct gmx_gpu_info_t;
@@ -47,10 +49,9 @@ struct t_commrec;
 
 namespace gmx
 {
-
 class HardwareTopology;
-
-} // namespace
+class MDLogger;
+}
 
 /*! \brief Return whether mdrun can use more than one GPU per node
  *
@@ -64,6 +65,11 @@ gmx_bool gmx_multiple_gpu_per_node_supported();
  * example. */
 gmx_bool gmx_gpu_sharing_supported();
 
+/*! \internal \brief
+ * Returns the GPU information text, one GPU per line.
+ */
+std::string sprint_gpus(const gmx_gpu_info_t *gpu_info);
+
 /*! \brief Run detection, consistency checks, and make available on all ranks.
  *
  * This routine constructs the global hwinfo structure and returns a pointer to
@@ -72,27 +78,23 @@ gmx_bool gmx_gpu_sharing_supported();
  * available on all nodes.
  * Caller is responsible for freeing this pointer.
  */
-gmx_hw_info_t *gmx_detect_hardware(FILE *fplog, const t_commrec *cr,
-                                   gmx_bool bDetectGPUs);
+gmx_hw_info_t *gmx_detect_hardware(const gmx::MDLogger &mdlog,
+                                   const t_commrec *cr, gmx_bool bDetectGPUs);
 
 /* Print information about the detected hardware to fplog (if != NULL)
  * and to stderr the master rank.
  */
 void gmx_print_detected_hardware(FILE *fplog, const t_commrec *cr,
+                                 const gmx::MDLogger &mdlog,
                                  const gmx_hw_info_t *hwinfo);
 
 void gmx_hardware_info_free(gmx_hw_info_t *hwinfo);
 
 void gmx_parse_gpu_ids(gmx_gpu_opt_t *gpu_opt);
 
-void gmx_select_gpu_ids(FILE *fplog, const t_commrec *cr,
-                        const gmx_gpu_info_t *gpu_info,
-                        gmx_bool bForceUseGPU,
-                        gmx_gpu_opt_t *gpu_opt);
-
 /* Check the consistency of hw_opt with hwinfo.
    This function should be called once on each MPI rank. */
-void gmx_check_hw_runconf_consistency(FILE                *fplog,
+void gmx_check_hw_runconf_consistency(const gmx::MDLogger &mdlog,
                                       const gmx_hw_info_t *hwinfo,
                                       const t_commrec     *cr,
                                       const gmx_hw_opt_t  *hw_opt,
diff --git a/src/gromacs/hardware/hardwareassign.cpp b/src/gromacs/hardware/hardwareassign.cpp
new file mode 100644 (file)
index 0000000..7efeedd
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+#include "gmxpre.h"
+
+#include "hardwareassign.h"
+
+#include "config.h"
+
+#include <cstring>
+
+#include <algorithm>
+#include <string>
+
+#include "gromacs/gmxlib/network.h"
+#include "gromacs/gpu_utils/gpu_utils.h"
+#include "gromacs/hardware/detecthardware.h"
+#include "gromacs/hardware/gpu_hw_info.h"
+#include "gromacs/mdtypes/commrec.h"
+#include "gromacs/utility/basenetwork.h"
+#include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/logger.h"
+#include "gromacs/utility/programcontext.h"
+#include "gromacs/utility/smalloc.h"
+#include "gromacs/utility/stringutil.h"
+#include "gromacs/utility/sysinfo.h"
+
+#define HOSTNAMELEN 80
+
+/*! \internal \brief
+ * Prints GPU information strings on this node into the stderr and log.
+ * Only used for logging errors in heterogenous MPI configurations.
+ */
+static void print_gpu_detection_stats(const gmx::MDLogger  &mdlog,
+                                      const gmx_gpu_info_t *gpu_info)
+{
+    char onhost[HOSTNAMELEN+10];
+    int  ngpu;
+
+    if (!gpu_info->bDetectGPUs)
+    {
+        /* We skipped the detection, so don't print detection stats */
+        return;
+    }
+
+    ngpu = gpu_info->n_dev;
+
+    /* We only print the detection on one, of possibly multiple, nodes */
+    std::strncpy(onhost, " on host ", 10);
+    gmx_gethostname(onhost + 9, HOSTNAMELEN);
+
+    if (ngpu > 0)
+    {
+        std::string gpuDesc = sprint_gpus(gpu_info);
+        GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                "%d GPU%s detected%s:\n%s",
+                ngpu, (ngpu > 1) ? "s" : "", onhost, gpuDesc.c_str());
+    }
+    else
+    {
+        GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted("No GPUs detected%s", onhost);
+    }
+    // FIXME: This currently only logs on the master rank, which defeats the purpose.
+    // A new MDLogger option is required for printing to stderr on all ranks.
+    // There is also a question of MPI reduction of the outputs, see Redmine issue #1505.
+}
+
+/*! \internal \brief
+ * This function is responsible for mapping the GPUs to the processes on a single node
+ * (filling the gpu_opt->dev_use array).
+ *
+ * \param[in,out]    gpu_opt              Input/output GPU assignment data.
+ * \param[in]        nrank                Number of PP GPU ranks on the node.
+ * \param[in]        rank                 Index of PP GPU rank on the node.
+ *
+ * This selects the GPUs we will use. This is an operation local to each physical node.
+ * If we have less MPI ranks than GPUs, we will waste some GPUs.
+ */
+static void assign_rank_gpu_ids(gmx_gpu_opt_t *gpu_opt, int nrank, int rank)
+{
+    GMX_RELEASE_ASSERT(gpu_opt, "Invalid gpu_opt pointer passed");
+    GMX_RELEASE_ASSERT(nrank >= 1,
+                       gmx::formatString("Invalid limit (%d) for the number of GPUs (detected %d compatible GPUs)",
+                                         rank, gpu_opt->n_dev_compatible).c_str());
+
+    if (gpu_opt->n_dev_compatible == 0)
+    {
+        char host[HOSTNAMELEN];
+
+        gmx_gethostname(host, HOSTNAMELEN);
+        gmx_fatal(FARGS, "A GPU was requested on host %s, but no compatible GPUs were detected. All nodes with PP ranks need to have GPUs. If you intended to use GPU acceleration in a parallel run, you can either avoid using the nodes that don't have GPUs or place PME ranks on these nodes.", host);
+    }
+
+    int nshare;
+
+    nshare = 1;
+    if (nrank > gpu_opt->n_dev_compatible)
+    {
+        if (nrank % gpu_opt->n_dev_compatible == 0)
+        {
+            nshare = gmx_gpu_sharing_supported() ? nrank/gpu_opt->n_dev_compatible : 1;
+        }
+        else
+        {
+            if (rank == 0)
+            {
+                gmx_fatal(FARGS, "The number of MPI ranks (%d) in a physical node is not a multiple of the number of GPUs (%d). Select a different number of MPI ranks or use the -gpu_id option to manually specify the GPU to be used.",
+                          nrank, gpu_opt->n_dev_compatible);
+            }
+
+#if GMX_MPI
+            /* We use a global barrier to prevent ranks from continuing with
+             * an invalid setup.
+             */
+            MPI_Barrier(MPI_COMM_WORLD);
+#endif
+        }
+    }
+
+    /* Here we will waste GPUs when nrank < gpu_opt->n_dev_compatible */
+    gpu_opt->n_dev_use = std::min(gpu_opt->n_dev_compatible*nshare, nrank);
+    if (!gmx_multiple_gpu_per_node_supported())
+    {
+        gpu_opt->n_dev_use = std::min(gpu_opt->n_dev_use, 1);
+    }
+    snew(gpu_opt->dev_use, gpu_opt->n_dev_use);
+    for (int i = 0; i != gpu_opt->n_dev_use; ++i)
+    {
+        /* TODO: improve this implementation: either sort GPUs or remove the weakest here */
+        gpu_opt->dev_use[i] = gpu_opt->dev_compatible[i/nshare];
+    }
+}
+
+void gmx_select_rank_gpu_ids(const gmx::MDLogger &mdlog, const t_commrec *cr,
+                             const gmx_gpu_info_t *gpu_info,
+                             gmx_bool bForceUseGPU,
+                             gmx_gpu_opt_t *gpu_opt)
+{
+    int              i;
+    char             sbuf[STRLEN], stmp[STRLEN];
+
+    /* Bail if binary is not compiled with GPU acceleration, but this is either
+     * explicitly (-nb gpu) or implicitly (gpu ID passed) requested. */
+    if (bForceUseGPU && (GMX_GPU == GMX_GPU_NONE))
+    {
+        gmx_fatal(FARGS, "GPU acceleration requested, but %s was compiled without GPU support!",
+                  gmx::getProgramContext().displayName());
+    }
+
+    if (!(cr->duty & DUTY_PP))
+    {
+        /* Our rank is not doing PP, we don't use a GPU */
+        return;
+    }
+
+    if (gpu_opt->bUserSet)
+    {
+        /* Check the GPU IDs passed by the user.
+         * (GPU IDs have been parsed by gmx_parse_gpu_ids before)
+         */
+        int *checkres;
+        int  res;
+
+        snew(checkres, gpu_opt->n_dev_use);
+
+        res = check_selected_gpus(checkres, gpu_info, gpu_opt);
+
+        if (!res)
+        {
+            const bool canHaveHeterogeneousNodes = GMX_LIB_MPI && PAR(cr);
+            if (canHaveHeterogeneousNodes)
+            {
+                print_gpu_detection_stats(mdlog, gpu_info);
+            }
+
+            sprintf(sbuf, "Some of the requested GPUs do not exist, behave strangely, or are not compatible:\n");
+            for (i = 0; i < gpu_opt->n_dev_use; i++)
+            {
+                if (checkres[i] != egpuCompatible)
+                {
+                    sprintf(stmp, "    GPU #%d: %s\n",
+                            gpu_opt->dev_use[i],
+                            gpu_detect_res_str[checkres[i]]);
+                    strcat(sbuf, stmp);
+                }
+            }
+            gmx_fatal(FARGS, "%s", sbuf);
+        }
+
+        sfree(checkres);
+    }
+    else if (getenv("GMX_EMULATE_GPU") == NULL)
+    {
+        pick_compatible_gpus(gpu_info, gpu_opt);
+        assign_rank_gpu_ids(gpu_opt, cr->nrank_pp_intranode, cr->rank_pp_intranode);
+    }
+
+    /* If the user asked for a GPU, check whether we have a GPU */
+    if (bForceUseGPU && gpu_info->n_dev_compatible == 0)
+    {
+        gmx_fatal(FARGS, "GPU acceleration requested, but no compatible GPUs were detected.");
+    }
+}
similarity index 64%
rename from src/gromacs/gmxlib/md_logging.h
rename to src/gromacs/hardware/hardwareassign.h
index 8da09734f09707d10d5748e3bad2e042a4b5b5f3..4a21617d3fe37262fce66d66464707e44cfe6941 100644 (file)
@@ -1,9 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2012,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  * To help us fund GROMACS development, we humbly ask that you cite
  * the research papers on the package. Check out http://www.gromacs.org.
  */
-#ifndef GMX_GMXLIB_MD_LOGGING_H
-#define GMX_GMXLIB_MD_LOGGING_H
+#ifndef GMX_HARDWARE_HARDWAREASSIGN_H
+#define GMX_HARDWARE_HARDWAREASSIGN_H
 
-#include <cstdio>
+#include "gromacs/utility/basedefinitions.h"
 
+struct gmx_gpu_info_t;
+struct gmx_gpu_opt_t;
 struct t_commrec;
 
-void md_print_info(const t_commrec *cr, FILE *fplog,
-                   const char *fmt, ...);
-/* Print an general information message to stderr on the master node
- * and to fplog if fplog!=NULL.
- * fmt is a standard printf formatting string which should end in \n,
- * the arguments after that contain the values to be printed, as in printf.
- */
+namespace gmx
+{
+class MDLogger;
+}
 
-void md_print_warn(const t_commrec *cr, FILE *fplog,
-                   const char *fmt, ...);
-/* As md_print_info above, but for important notices or warnings.
- * The only difference with md_print_info is that a newline is printed
- * before and after the message such that it stands out.
- */
+void gmx_select_rank_gpu_ids(const gmx::MDLogger &mdlog, const t_commrec *cr,
+                             const gmx_gpu_info_t *gpu_info,
+                             gmx_bool bForceUseGPU,
+                             gmx_gpu_opt_t *gpu_opt);
 
 #endif
index 84b8e3cb38acf71ad462f96889de05cd537dc621..dfe5dbaec0144dcaec5ff8e0e38bfc2d9136a36d 100644 (file)
@@ -582,13 +582,6 @@ HardwareTopology HardwareTopology::detect()
 {
     HardwareTopology result;
 
-    // Default values for machine and numa stuff
-    result.machine_.logicalProcessorCount   = 0;
-    result.machine_.numa.baseLatency        = 0.0;
-    result.machine_.numa.maxRelativeLatency = 0.0;
-    result.supportLevel_                    = SupportLevel::None;
-    result.isThisSystem_                    = true;
-
 #if GMX_HWLOC
     parseHwLoc(&result.machine_, &result.supportLevel_, &result.isThisSystem_);
 #endif
@@ -613,12 +606,33 @@ HardwareTopology HardwareTopology::detect()
     return result;
 }
 
+HardwareTopology::Machine::Machine()
+{
+    logicalProcessorCount   = 0;
+    numa.baseLatency        = 0.0;
+    numa.maxRelativeLatency = 0.0;
+}
+
 
 HardwareTopology::HardwareTopology()
-    : supportLevel_(SupportLevel::None)
+    : supportLevel_(SupportLevel::None),
+      machine_(),
+      isThisSystem_(true)
 {
 }
 
+HardwareTopology::HardwareTopology(int logicalProcessorCount)
+    : supportLevel_(SupportLevel::None),
+      machine_(),
+      isThisSystem_(true)
+{
+    if (logicalProcessorCount > 0)
+    {
+        machine_.logicalProcessorCount = logicalProcessorCount;
+        supportLevel_                  = SupportLevel::LogicalProcessorCount;
+    }
+}
+
 int HardwareTopology::numberOfCores() const
 {
     if (supportLevel() >= SupportLevel::Basic)
index f766a4d695d9eeb4266a5a1eac1ff069d6276f20..b2dcf352cb8fe65511f50cc06babb039e7216567 100644 (file)
@@ -177,6 +177,8 @@ class HardwareTopology
          */
         struct Machine
         {
+            Machine();
+
             int                            logicalProcessorCount; //!< Number of logical processors in system
             std::vector<LogicalProcessor>  logicalProcessors;     //!< Map logical processors to socket/core
             std::vector<Socket>            sockets;               //!< All the sockets in the system
@@ -190,6 +192,14 @@ class HardwareTopology
         /*! \brief Detects the hardware topology. */
         static HardwareTopology detect();
 
+        /*! \brief Creates a topology with given number of logical cores.
+         *
+         * The support level will be either None or LogicalProcessorCount.
+         *
+         * Intended for testing of code that uses the hardware topology.
+         */
+        explicit HardwareTopology(int logicalProcessorCount);
+
         /*! \brief Check what topology information that is available and valid
          *
          *  The amount of hardware topology information that can be detected depends
index 2908c7b9f285834356d75929741e44507b1ce7aa..7848a959ac53b5f473ea93535e89761fe68a66fc 100644 (file)
@@ -70,6 +70,7 @@
 #include "gromacs/imd/imdsocket.h"
 #include "gromacs/math/units.h"
 #include "gromacs/math/vec.h"
+#include "gromacs/mdlib/broadcaststructs.h"
 #include "gromacs/mdlib/groupcoord.h"
 #include "gromacs/mdlib/mdrun.h"
 #include "gromacs/mdlib/sighandler.h"
 /*! \brief IMD Protocol Version. */
 #define IMDVERSION 2
 
-/*! \brief Broadcast d to all nodes */
-#define  block_bc(cr, d) gmx_bcast(sizeof(d), &(d), (cr))
-
-/*! \brief Broadcast nr elements of d to all nodes */
-#define  nblock_bc(cr, nr, d) gmx_bcast((nr)*sizeof((d)[0]), (d), (cr))
-
 
 /*! \internal
  * \brief
@@ -442,7 +437,7 @@ void write_IMDgroup_to_file(gmx_bool bIMD, t_inputrec *ir, t_state *state,
     {
         IMDatoms = gmx_mtop_global_atoms(sys);
         write_sto_conf_indexed(opt2fn("-imd", nfile, fnm), "IMDgroup", &IMDatoms,
-                               state->x, state->v, ir->ePBC, state->box, ir->imd->nat, ir->imd->ind);
+                               as_rvec_array(state->x.data()), as_rvec_array(state->v.data()), ir->ePBC, state->box, ir->imd->nat, ir->imd->ind);
     }
 }
 
index 03185f084316873609abe9187ec32a6e034729fe..a63915e096094722ab28b4c4cf9e93de1123e254 100644 (file)
@@ -1647,7 +1647,7 @@ L65:
         F77_FUNC(dgemv, DGEMV) ("T", n, &iwork[12], &c_b18, &v[v_offset], ldv, &workd[iwork[8]],
                                 &c__1, &c_b42, &workd[iwork[9]], &c__1);
     }
-    else if (*mode == 2)
+    else
     {
         F77_FUNC(dgemv, DGEMV) ("T", n, &iwork[12], &c_b18, &v[v_offset], ldv, &workd[iwork[10]
                                 ], &c__1, &c_b42, &workd[iwork[9]], &c__1);
@@ -4510,7 +4510,7 @@ L65:
         F77_FUNC(sgemv, SGEMV) ("T", n, &iwork[12], &c_b18, &v[v_offset], ldv, &workd[iwork[8]],
                                 &c__1, &c_b42, &workd[iwork[9]], &c__1);
     }
-    else if (*mode == 2)
+    else
     {
         F77_FUNC(sgemv, SGEMV) ("T", n, &iwork[12], &c_b18, &v[v_offset], ldv, &workd[iwork[10]
                                 ], &c__1, &c_b42, &workd[iwork[9]], &c__1);
index 950d9392aac3d2501b6079bd3a4ba988c43192f0..7c9fdb5aae5f3e7d8469aa578147ad52ad1ddad1 100644 (file)
@@ -48,7 +48,7 @@ F77_FUNC(dbdsqr,DBDSQR)(const char *uplo,
     double unfl, sinl, cosr, smin, smax, sinr;
     double oldcs;
     int oldll;
-    double shift, sigmn, oldsn;
+    double shift, sigmn, oldsn = 0.;
     int maxit;
     double sminl;
     double sigmx;
index 0b3004b0693bf89a993a04483d7ee9aecc7ed3b0..a9513588b193c1be5e9abf799a2d628fb2187ac2 100644 (file)
@@ -121,6 +121,7 @@ F77_FUNC(dstebz,DSTEBZ)(const char *range,
     ulp = 2*GMX_DOUBLE_EPS;
     rtoli = ulp * 2.;
     nb = DSTEBZ_BLOCKSIZE;
+    // cppcheck-suppress knownConditionTrueFalse
     if (nb <= 1) {
        nb = 0;
     }
index 2cd91a2fe4ac5ad5aa12bf7c42194fe443b407d8..18f302a5153242669b663caf30411215a02dca10 100644 (file)
@@ -48,7 +48,7 @@ F77_FUNC(sbdsqr,SBDSQR)(const char *uplo,
     float unfl, sinl, cosr, smin, smax, sinr;
     float oldcs;
     int oldll;
-    float shift, sigmn, oldsn;
+    float shift, sigmn, oldsn = 0.;
     int maxit;
     float sminl;
     float sigmx;
index 652f2cc539fab215868ba8b78db6c99de9048235..26ed314ae049e32e59764148afb1f4f48561ce3a 100644 (file)
@@ -121,6 +121,7 @@ F77_FUNC(sstebz,SSTEBZ)(const char *range,
     ulp = 2*GMX_FLOAT_EPS;
     rtoli = ulp * 2.;
     nb = DSTEBZ_BLOCKSIZE;
+    // cppcheck-suppress knownConditionTrueFalse
     if (nb <= 1) {
        nb = 0;
     }
index f56c61cb81c9e4d161b427546d5d3a8453289573..10d77d224c19e0240d6ba2eaf90302d086b4be2c 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2014,2015, by the GROMACS development team, led by
+# Copyright (c) 2014,2015,2016, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -38,5 +38,5 @@ set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${LISTED_FORCES_SOURCES} PARENT_SCO
 gmx_install_headers(listed-forces.h)
 
 if (BUILD_TESTING)
-#    add_subdirectory(tests)
+     add_subdirectory(tests)
 endif()
index 44ac6e3f25462fb2f79388d452bc82db2a9caece..93be131e79b92208f5dbdaad910b82511a9a2fd4 100644 (file)
@@ -76,7 +76,6 @@ void init_orires(FILE *fplog, const gmx_mtop_t *mtop,
     gmx_mtop_ilistloop_t    iloop;
     t_ilist                *il;
     gmx_mtop_atomloop_all_t aloop;
-    t_atom                 *atom;
     const gmx_multisim_t   *ms;
 
     od->nr = gmx_mtop_ftype_count(mtop, F_ORIRES);
@@ -209,6 +208,7 @@ void init_orires(FILE *fplog, const gmx_mtop_t *mtop,
     mtot  = 0.0;
     j     = 0;
     aloop = gmx_mtop_atomloop_all_init(mtop);
+    const t_atom *atom;
     while (gmx_mtop_atomloop_all_next(aloop, &i, &atom))
     {
         if (mtop->groups.grpnr[egcORFIT] == NULL ||
index 34416aa18835cd9f5df818b146f28c0df57cceb1..28084ebf685dd663e5fd68951efbb46833fd2b5b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -397,7 +397,7 @@ posres_wrapper(t_nrnb             *nrnb,
     dvdl = 0;
     v    = posres(idef->il[F_POSRES].nr, idef->il[F_POSRES].iatoms,
                   idef->iparams_posres,
-                  x, fr->f_novirsum, fr->vir_diag_posres,
+                  x, as_rvec_array(fr->f_novirsum->data()), fr->vir_diag_posres,
                   fr->ePBC == epbcNONE ? NULL : pbc,
                   lambda[efptRESTRAINT], &dvdl,
                   fr->rc_scaling, fr->ePBC, fr->posres_com, fr->posres_comB);
@@ -456,7 +456,7 @@ void fbposres_wrapper(t_nrnb             *nrnb,
 
     v = fbposres(idef->il[F_FBPOSRES].nr, idef->il[F_FBPOSRES].iatoms,
                  idef->iparams_fbposres,
-                 x, fr->f_novirsum, fr->vir_diag_posres,
+                 x, as_rvec_array(fr->f_novirsum->data()), fr->vir_diag_posres,
                  fr->ePBC == epbcNONE ? NULL : pbc,
                  fr->rc_scaling, fr->ePBC, fr->posres_com);
     enerd->term[F_FBPOSRES] += v;
diff --git a/src/gromacs/listed-forces/tests/CMakeLists.txt b/src/gromacs/listed-forces/tests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..254fc1b
--- /dev/null
@@ -0,0 +1,37 @@
+#
+# This file is part of the GROMACS molecular simulation package.
+#
+# Copyright (c) 2016, by the GROMACS development team, led by
+# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+# and including many others, as listed in the AUTHORS file in the
+# top-level source directory and at http://www.gromacs.org.
+#
+# GROMACS is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1
+# of the License, or (at your option) any later version.
+#
+# GROMACS is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with GROMACS; if not, see
+# http://www.gnu.org/licenses, or write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+#
+# If you want to redistribute modifications to GROMACS, please
+# consider that scientific software is very special. Version
+# control is crucial - bugs must be traceable. We will be happy to
+# consider code for inclusion in the official distribution, but
+# derived work must not be called official GROMACS. Details are found
+# in the README & COPYING files - if they are missing, get the
+# official version at http://www.gromacs.org.
+#
+# To help us fund GROMACS development, we humbly ask that you cite
+# the research papers on the package. Check out http://www.gromacs.org.
+
+gmx_add_unit_test(ListedForcesTest listed-forces-test
+  bonded.cpp)
+
diff --git a/src/gromacs/listed-forces/tests/bonded.cpp b/src/gromacs/listed-forces/tests/bonded.cpp
new file mode 100644 (file)
index 0000000..e49f2a2
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Implements test of bonded force routines
+ *
+ * \author David van der Spoel <david.vanderspoel@icm.uu.se>
+ * \ingroup module_listed-forces
+ */
+#include "gmxpre.h"
+
+#include "gromacs/listed-forces/bonded.h"
+
+#include <cmath>
+
+#include <memory>
+
+#include <gtest/gtest.h>
+
+#include "gromacs/math/units.h"
+#include "gromacs/pbcutil/ishift.h"
+#include "gromacs/pbcutil/pbc.h"
+
+#include "testutils/refdata.h"
+#include "testutils/testasserts.h"
+#include "testutils/testfilemanager.h"
+
+namespace gmx
+{
+namespace
+{
+
+//! Number of atoms used in these tests.
+#define NATOMS 4
+
+class BondedTest : public ::testing::Test
+{
+    protected:
+        rvec   x[NATOMS];
+        matrix box;
+        test::TestReferenceData           refData_;
+        test::TestReferenceChecker        checker_;
+        BondedTest( ) :
+            checker_(refData_.rootChecker())
+        {
+            test::FloatingPointTolerance tolerance(test::relativeToleranceAsFloatingPoint(1.0, 1e-6));
+            checker_.setDefaultTolerance(tolerance);
+            clear_rvecs(NATOMS, x);
+            x[1][2] = 1;
+            x[2][1] = x[2][2] = 1;
+            x[3][0] = x[3][1] = x[3][2] = 1;
+
+            clear_mat(box);
+            box[0][0] = box[1][1] = box[2][2] = 1.5;
+        }
+
+        void testBondAngle(int epbc)
+        {
+            rvec  r_ij, r_kj;
+            real  cosine_angle, angle;
+            int   t1, t2;
+            t_pbc pbc;
+
+            set_pbc(&pbc, epbc, box);
+            angle = bond_angle(x[0], x[1], x[2], &pbc,
+                               r_ij, r_kj, &cosine_angle,
+                               &t1, &t2);
+            checker_.checkReal(angle, "angle");
+            checker_.checkReal(cosine_angle, "cosine_angle");
+            checker_.checkInteger(t1, "t1");
+            checker_.checkInteger(t2, "t2");
+        }
+
+        void testDihedralAngle(int epbc)
+        {
+            rvec  r_ij, r_kj, r_kl, m, n;
+            real  cosine_angle, angle;
+            int   t1, t2, t3;
+            t_pbc pbc;
+
+            set_pbc(&pbc, epbc, box);
+            angle = dih_angle(x[0], x[1], x[2], x[3], &pbc,
+                              r_ij, r_kj, r_kl, m, n, &cosine_angle,
+                              &t1, &t2, &t3);
+
+            checker_.checkReal(angle, "angle");
+            checker_.checkReal(cosine_angle, "cosine_angle");
+            checker_.checkInteger(t1, "t1");
+            checker_.checkInteger(t2, "t2");
+            checker_.checkInteger(t3, "t3");
+        }
+
+        void testIfunc(int                         ftype,
+                       const std::vector<t_iatom> &iatoms,
+                       const t_iparams             iparams[],
+                       int                         epbc)
+        {
+            real  lambda = 0;
+            real  dvdlambda;
+            rvec4 f[NATOMS];
+            for (int i = 0; i < NATOMS; i++)
+            {
+                for (int j = 0; j < 4; j++)
+                {
+                    f[i][j] = 0;
+                }
+            }
+            rvec  fshift[N_IVEC];
+            clear_rvecs(N_IVEC, fshift);
+            t_pbc pbc;
+            set_pbc(&pbc, epbc, box);
+            int   ddgatindex = 0;
+            real  energy     = interaction_function[ftype].ifunc(iatoms.size(),
+                                                                 iatoms.data(),
+                                                                 iparams,
+                                                                 x, f, fshift,
+                                                                 &pbc,
+                                                                 /* const struct t_graph *g */ NULL,
+                                                                 lambda, &dvdlambda,
+                                                                 /* const struct t_mdatoms *md */ NULL,
+                                                                 /* struct t_fcdata *fcd */ NULL,
+                                                                 &ddgatindex);
+            checker_.checkReal(energy, interaction_function[ftype].longname);
+        }
+
+};
+
+TEST_F (BondedTest, BondAnglePbcNone)
+{
+    testBondAngle(epbcNONE);
+}
+
+TEST_F (BondedTest, BondAnglePbcXy)
+{
+    testBondAngle(epbcXY);
+}
+
+TEST_F (BondedTest, BondAnglePbcXyz)
+{
+    testBondAngle(epbcXYZ);
+}
+
+TEST_F (BondedTest, DihedralAnglePbcNone)
+{
+    testDihedralAngle(epbcNONE);
+}
+
+TEST_F (BondedTest, DihedralAnglePbcXy)
+{
+    testDihedralAngle(epbcXY);
+}
+
+TEST_F (BondedTest, DihedarlAnglePbcXyz)
+{
+    testDihedralAngle(epbcXYZ);
+}
+
+TEST_F (BondedTest, IfuncBondsPbcNo)
+{
+    std::vector<t_iatom> iatoms = { 0, 0, 1, 0, 1, 2, 0, 2, 3 };
+    t_iparams            iparams;
+    iparams.harmonic.rA  = iparams.harmonic.rB  = 0.8;
+    iparams.harmonic.krA = iparams.harmonic.krB = 50;
+    testIfunc(F_BONDS, iatoms, &iparams, epbcNONE);
+}
+
+TEST_F (BondedTest, IfuncBondsPbcXy)
+{
+    std::vector<t_iatom> iatoms = { 0, 0, 1, 0, 1, 2, 0, 2, 3 };
+    t_iparams            iparams;
+    iparams.harmonic.rA  = iparams.harmonic.rB  = 0.8;
+    iparams.harmonic.krA = iparams.harmonic.krB = 50;
+    testIfunc(F_BONDS, iatoms, &iparams, epbcXY);
+}
+
+TEST_F (BondedTest, IfuncBondsPbcXyz)
+{
+    std::vector<t_iatom> iatoms = { 0, 0, 1, 0, 1, 2, 0, 2, 3 };
+    t_iparams            iparams;
+    iparams.harmonic.rA  = iparams.harmonic.rB  = 0.8;
+    iparams.harmonic.krA = iparams.harmonic.krB = 50;
+    testIfunc(F_BONDS, iatoms, &iparams, epbcXYZ);
+}
+
+TEST_F (BondedTest, IfuncAnglesPbcNo)
+{
+    std::vector<t_iatom> iatoms = { 0, 0, 1, 2, 0, 1, 2, 3 };
+    t_iparams            iparams;
+    real                 k = 50;
+    iparams.harmonic.rA  = iparams.harmonic.rB  = 100;
+    iparams.harmonic.krA = iparams.harmonic.krB = k;
+    testIfunc(F_ANGLES, iatoms, &iparams, epbcNONE);
+}
+
+TEST_F (BondedTest, IfuncAnglesPbcXy)
+{
+    std::vector<t_iatom> iatoms  = { 0, 0, 1, 2, 0, 1, 2, 3 };
+    t_iparams            iparams;
+    real                 k = 50;
+    iparams.harmonic.rA  = iparams.harmonic.rB  = 100;
+    iparams.harmonic.krA = iparams.harmonic.krB = k;
+    testIfunc(F_ANGLES, iatoms, &iparams, epbcXY);
+}
+
+TEST_F (BondedTest, IfuncAnglesPbcXYZ)
+{
+    std::vector<t_iatom> iatoms = { 0, 0, 1, 2, 0, 1, 2, 3 };
+    t_iparams            iparams;
+    real                 k = 50;
+    iparams.harmonic.rA  = iparams.harmonic.rB  = 100;
+    iparams.harmonic.krA = iparams.harmonic.krB = k;
+    testIfunc(F_ANGLES, iatoms, &iparams, epbcXYZ);
+}
+
+TEST_F (BondedTest, IfuncProperDihedralsPbcNo)
+{
+    std::vector<t_iatom> iatoms = { 0, 0, 1, 2, 3 };
+    t_iparams            iparams;
+    iparams.pdihs.phiA = iparams.pdihs.phiB = -100;
+    iparams.pdihs.cpA  = iparams.pdihs.cpB  = 10;
+    iparams.pdihs.mult = 1;
+    testIfunc(F_PDIHS, iatoms, &iparams, epbcNONE);
+}
+
+TEST_F (BondedTest, IfuncProperDihedralsPbcXy)
+{
+    std::vector<t_iatom> iatoms = { 0, 0, 1, 2, 3 };
+    t_iparams            iparams;
+    iparams.pdihs.phiA = iparams.pdihs.phiB = -100;
+    iparams.pdihs.cpA  = iparams.pdihs.cpB  = 10;
+    iparams.pdihs.mult = 1;
+    testIfunc(F_PDIHS, iatoms, &iparams, epbcXY);
+}
+
+TEST_F (BondedTest, IfuncProperDihedralsPbcXyz)
+{
+    std::vector<t_iatom> iatoms  = { 0, 0, 1, 2, 3 };
+    t_iparams            iparams;
+    iparams.pdihs.phiA = iparams.pdihs.phiB = -100;
+    iparams.pdihs.cpA  = iparams.pdihs.cpB  = 10;
+    iparams.pdihs.mult = 1;
+    testIfunc(F_PDIHS, iatoms, &iparams, epbcXYZ);
+}
+
+}
+
+}
diff --git a/src/gromacs/listed-forces/tests/refdata/BondedTest_BondAnglePbcNone.xml b/src/gromacs/listed-forces/tests/refdata/BondedTest_BondAnglePbcNone.xml
new file mode 100644 (file)
index 0000000..d84a3e1
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="angle">1.5707964</Real>
+  <Real Name="cosine_angle">0</Real>
+  <Int Name="t1">22</Int>
+  <Int Name="t2">22</Int>
+</ReferenceData>
diff --git a/src/gromacs/listed-forces/tests/refdata/BondedTest_BondAnglePbcXy.xml b/src/gromacs/listed-forces/tests/refdata/BondedTest_BondAnglePbcXy.xml
new file mode 100644 (file)
index 0000000..0f7474a
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="angle">1.5707964</Real>
+  <Real Name="cosine_angle">0</Real>
+  <Int Name="t1">22</Int>
+  <Int Name="t2">17</Int>
+</ReferenceData>
diff --git a/src/gromacs/listed-forces/tests/refdata/BondedTest_BondAnglePbcXyz.xml b/src/gromacs/listed-forces/tests/refdata/BondedTest_BondAnglePbcXyz.xml
new file mode 100644 (file)
index 0000000..5d778a1
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="angle">1.5707964</Real>
+  <Real Name="cosine_angle">0</Real>
+  <Int Name="t1">37</Int>
+  <Int Name="t2">17</Int>
+</ReferenceData>
diff --git a/src/gromacs/listed-forces/tests/refdata/BondedTest_DihedarlAnglePbcXyz.xml b/src/gromacs/listed-forces/tests/refdata/BondedTest_DihedarlAnglePbcXyz.xml
new file mode 100644 (file)
index 0000000..8941df4
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="angle">1.5707964</Real>
+  <Real Name="cosine_angle">1</Real>
+  <Int Name="t1">37</Int>
+  <Int Name="t2">17</Int>
+  <Int Name="t3">23</Int>
+</ReferenceData>
diff --git a/src/gromacs/listed-forces/tests/refdata/BondedTest_DihedralAnglePbcNone.xml b/src/gromacs/listed-forces/tests/refdata/BondedTest_DihedralAnglePbcNone.xml
new file mode 100644 (file)
index 0000000..5458d88
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="angle">-1.5707964</Real>
+  <Real Name="cosine_angle">-1</Real>
+  <Int Name="t1">22</Int>
+  <Int Name="t2">22</Int>
+  <Int Name="t3">22</Int>
+</ReferenceData>
diff --git a/src/gromacs/listed-forces/tests/refdata/BondedTest_DihedralAnglePbcXy.xml b/src/gromacs/listed-forces/tests/refdata/BondedTest_DihedralAnglePbcXy.xml
new file mode 100644 (file)
index 0000000..3bf5d9b
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="angle">-1.5707964</Real>
+  <Real Name="cosine_angle">-1</Real>
+  <Int Name="t1">22</Int>
+  <Int Name="t2">17</Int>
+  <Int Name="t3">23</Int>
+</ReferenceData>
diff --git a/src/gromacs/listed-forces/tests/refdata/BondedTest_IfuncAnglesPbcNo.xml b/src/gromacs/listed-forces/tests/refdata/BondedTest_IfuncAnglesPbcNo.xml
new file mode 100644 (file)
index 0000000..0bf9b85
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="Angle">1.5230865</Real>
+</ReferenceData>
diff --git a/src/gromacs/listed-forces/tests/refdata/BondedTest_IfuncAnglesPbcXYZ.xml b/src/gromacs/listed-forces/tests/refdata/BondedTest_IfuncAnglesPbcXYZ.xml
new file mode 100644 (file)
index 0000000..0bf9b85
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="Angle">1.5230865</Real>
+</ReferenceData>
diff --git a/src/gromacs/listed-forces/tests/refdata/BondedTest_IfuncAnglesPbcXy.xml b/src/gromacs/listed-forces/tests/refdata/BondedTest_IfuncAnglesPbcXy.xml
new file mode 100644 (file)
index 0000000..0bf9b85
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="Angle">1.5230865</Real>
+</ReferenceData>
diff --git a/src/gromacs/listed-forces/tests/refdata/BondedTest_IfuncBondsPbcNo.xml b/src/gromacs/listed-forces/tests/refdata/BondedTest_IfuncBondsPbcNo.xml
new file mode 100644 (file)
index 0000000..71c61f3
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="Bond">2.9999995</Real>
+</ReferenceData>
diff --git a/src/gromacs/listed-forces/tests/refdata/BondedTest_IfuncBondsPbcXy.xml b/src/gromacs/listed-forces/tests/refdata/BondedTest_IfuncBondsPbcXy.xml
new file mode 100644 (file)
index 0000000..8582d6a
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="Bond">5.5</Real>
+</ReferenceData>
diff --git a/src/gromacs/listed-forces/tests/refdata/BondedTest_IfuncBondsPbcXyz.xml b/src/gromacs/listed-forces/tests/refdata/BondedTest_IfuncBondsPbcXyz.xml
new file mode 100644 (file)
index 0000000..2d98ef2
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="Bond">6.75</Real>
+</ReferenceData>
diff --git a/src/gromacs/listed-forces/tests/refdata/BondedTest_IfuncProperDihedralsPbcNo.xml b/src/gromacs/listed-forces/tests/refdata/BondedTest_IfuncProperDihedralsPbcNo.xml
new file mode 100644 (file)
index 0000000..47d7e15
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="Proper Dih.">19.848078</Real>
+</ReferenceData>
diff --git a/src/gromacs/listed-forces/tests/refdata/BondedTest_IfuncProperDihedralsPbcXy.xml b/src/gromacs/listed-forces/tests/refdata/BondedTest_IfuncProperDihedralsPbcXy.xml
new file mode 100644 (file)
index 0000000..47d7e15
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="Proper Dih.">19.848078</Real>
+</ReferenceData>
diff --git a/src/gromacs/listed-forces/tests/refdata/BondedTest_IfuncProperDihedralsPbcXyz.xml b/src/gromacs/listed-forces/tests/refdata/BondedTest_IfuncProperDihedralsPbcXyz.xml
new file mode 100644 (file)
index 0000000..f8dc6c0
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="Proper Dih.">0.1519227</Real>
+</ReferenceData>
index 181e149961af825babb45d25ee213da37ec54369..e57c053241a1f4a10cd3054ef715922c8ad3da20 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+# Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -45,6 +45,7 @@ gmx_install_headers(
     utilities.h
     vec.h
     vectypes.h
+    paddedvector.h
     )
 
 if (BUILD_TESTING)
diff --git a/src/gromacs/math/paddedvector.h b/src/gromacs/math/paddedvector.h
new file mode 100644 (file)
index 0000000..7b73dee
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \file
+ * \brief
+ * Declares gmx::PaddedRVecVector
+ *
+ * \author Mark Abraham <mark.j.abraham@gmail.com>
+ * \inpublicapi
+ * \ingroup module_math
+ */
+#ifndef GMX_MATH_PADDEDVECTOR_H
+#define GMX_MATH_PADDEDVECTOR_H
+
+#include <vector>
+
+#include "gromacs/math/vectypes.h"
+
+namespace gmx
+{
+
+/*! \brief Temporary definition of a type usable for SIMD-style loads of RVec quantities.
+ *
+ * \todo This vector is not padded yet, padding will be added soon */
+using PaddedRVecVector = std::vector<gmx::RVec>;
+
+} // namespace gmx
+
+// TODO This is a hack to avoid littering gmx:: all over code that is
+// almost all destined to move into the gmx namespace at some point.
+// An alternative would be about 20 files with using statements.
+using gmx::PaddedRVecVector;
+
+#endif
index 94fe43128c4f99ea808b287fe5bf9b05d71da0d8..30505b0e5fc795a896b3ee61228ca8a42363eb05 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -61,7 +61,7 @@ using gmx::RVec;
 TEST(RVecTest, CanBeStoredInVector)
 {
     std::vector<RVec> v;
-    v.push_back(RVec(1, 2, 3));
+    v.emplace_back(1, 2, 3);
     v.resize(2);
     EXPECT_EQ(1, v[0][XX]);
     EXPECT_EQ(2, v[0][YY]);
@@ -72,7 +72,7 @@ TEST(RVecTest, ConvertsImplicitlyFrom_rvec)
 {
     std::vector<RVec> v;
     rvec              x = { 1, 2, 3 };
-    v.push_back(x);
+    v.emplace_back(x);
     EXPECT_EQ(1, v[0][XX]);
     EXPECT_EQ(2, v[0][YY]);
     EXPECT_EQ(3, v[0][ZZ]);
@@ -81,7 +81,7 @@ TEST(RVecTest, ConvertsImplicitlyFrom_rvec)
 TEST(RVecTest, ConvertsImplicitlyTo_rvec)
 {
     std::vector<RVec> v;
-    v.push_back(RVec(1, 2, 3));
+    v.emplace_back(1, 2, 3);
     rvec              x;
     copy_rvec(v[0], x);
     EXPECT_EQ(1, x[XX]);
@@ -92,7 +92,7 @@ TEST(RVecTest, ConvertsImplicitlyTo_rvec)
 TEST(RVecTest, WorksAsMutable_rvec)
 {
     std::vector<RVec> v;
-    v.push_back(RVec(1, 2, 3));
+    v.emplace_back(1, 2, 3);
     rvec              x = {2, 3, 4};
     copy_rvec(x, v[0]);
     EXPECT_EQ(2, v[0][XX]);
@@ -103,8 +103,8 @@ TEST(RVecTest, WorksAsMutable_rvec)
 TEST(RVecTest, WorksAs_rvec_Array)
 {
     std::vector<RVec> v;
-    v.push_back(RVec(1, 2, 3));
-    v.push_back(RVec(2, 3, 4));
+    v.emplace_back(1, 2, 3);
+    v.emplace_back(2, 3, 4);
     const rvec *r = as_rvec_array(v.data());
     EXPECT_EQ(1, r[0][XX]);
     EXPECT_EQ(2, r[0][YY]);
diff --git a/src/gromacs/math/veccompare.cpp b/src/gromacs/math/veccompare.cpp
new file mode 100644 (file)
index 0000000..54eece9
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2004, The GROMACS development team.
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+#include "gmxpre.h"
+
+#include "veccompare.h"
+
+#include <cmath>
+#include <cstdio>
+
+#include "gromacs/utility/compare.h"
+
+void cmp_rvec(FILE *fp, const char *s, int index, const rvec i1, const rvec i2, real ftol, real abstol)
+{
+    if (!equal_real(i1[XX], i2[XX], ftol, abstol) ||
+        !equal_real(i1[YY], i2[YY], ftol, abstol) ||
+        !equal_real(i1[ZZ], i2[ZZ], ftol, abstol))
+    {
+        if (index != -1)
+        {
+            fprintf(fp, "%s[%5d] (%12.5e %12.5e %12.5e) - (%12.5e %12.5e %12.5e)\n",
+                    s, index, i1[XX], i1[YY], i1[ZZ], i2[XX], i2[YY], i2[ZZ]);
+        }
+        else
+        {
+            fprintf(fp, "%s (%12.5e %12.5e %12.5e) - (%12.5e %12.5e %12.5e)\n",
+                    s, i1[XX], i1[YY], i1[ZZ], i2[XX], i2[YY], i2[ZZ]);
+        }
+    }
+}
+
+void cmp_ivec(FILE *fp, const char *s, int index, const ivec i1, const ivec i2)
+{
+    if ((i1[XX] != i2[XX]) || (i1[YY] != i2[YY]) || (i1[ZZ] != i2[ZZ]))
+    {
+        if (index != -1)
+        {
+            fprintf(fp, "%s[%5d] (%8d,%8d,%8d - %8d,%8d,%8d)\n", s, index,
+                    i1[XX], i1[YY], i1[ZZ], i2[XX], i2[YY], i2[ZZ]);
+        }
+        else
+        {
+            fprintf(fp, "%s (%8d,%8d,%8d - %8d,%8d,%8d)\n", s,
+                    i1[XX], i1[YY], i1[ZZ], i2[XX], i2[YY], i2[ZZ]);
+        }
+    }
+}
+
+static void cmp_rvecs_rmstol(FILE *fp, const char *title, int n, const rvec x1[], const rvec x2[],
+                             real ftol, real abstol)
+{
+    int    i, m;
+    double rms;
+
+    /* For a vector you are usally not interested in a relative difference
+     * on a component that is very small compared to the other components.
+     * Therefore we do the relative comparision relative to the RMS component.
+     */
+    rms = 0.0;
+    for (i = 0; (i < n); i++)
+    {
+        for (m = 0; m < DIM; m++)
+        {
+            rms += x1[i][m]*x1[i][m] + x2[i][m]*x2[i][m];
+        }
+    }
+    rms = sqrt(rms/(2*n*DIM));
+
+    /* Convert the relative tolerance into an absolute tolerance */
+    if (ftol*rms < abstol)
+    {
+        abstol = ftol*rms;
+    }
+
+    /* And now do the actual comparision */
+    for (i = 0; (i < n); i++)
+    {
+        cmp_rvec(fp, title, i, x1[i], x2[i], 0.0, abstol);
+    }
+}
+
+void cmp_rvecs(FILE *fp, const char *title, int n, const rvec x1[], const rvec x2[],
+               gmx_bool bRMSD, real ftol, real abstol)
+{
+    int    i, m;
+    double d, ssd;
+
+    if (bRMSD)
+    {
+        ssd = 0;
+        for (i = 0; (i < n); i++)
+        {
+            for (m = 0; m < DIM; m++)
+            {
+                d    = x1[i][m] - x2[i][m];
+                ssd += d*d;
+            }
+        }
+        fprintf(fp, "%s RMSD %g\n", title, std::sqrt(ssd/n));
+    }
+    else
+    {
+        cmp_rvecs_rmstol(fp, title, n, x1, x2, ftol, abstol);
+    }
+}
similarity index 70%
rename from src/gromacs/tools/compare.h
rename to src/gromacs/math/veccompare.h
index 1ea889841a8e9225933c83bb8eea35f1f553c315..4b8ccca57598e4b5151e6a09d53ff4d5e5870a41 100644 (file)
  * To help us fund GROMACS development, we humbly ask that you cite
  * the research papers on the package. Check out http://www.gromacs.org.
  */
+#ifndef GMX_MATH_VECCOMPARE_H
+#define GMX_MATH_VECCOMPARE_H
 
-#ifndef GMX_TOOLS_COMPARE_H
-#define GMX_TOOLS_COMPARE_H
+#include <cstdio>
 
-struct gmx_output_env_t;
+#include "gromacs/math/vectypes.h"
+#include "gromacs/utility/basedefinitions.h"
+#include "gromacs/utility/real.h"
 
-/* Routines for comparing data structures from non-trajectory binary
-   file formats (e.g. as used by gmx check). */
+void cmp_rvec(FILE *fp, const char *s, int index, const rvec i1, const rvec i2, real ftol, real abstol);
 
-void
-comp_tpx(const char *fn1, const char *fn2, gmx_bool bRMSD, real ftol, real abstol);
-/* Compare two binary run input files */
+void cmp_ivec(FILE *fp, const char *s, int index, const ivec i1, const ivec i2);
 
-void comp_tpx_a_and_b_states(const char *fn, real ftol, real abstol);
-/* Compare two A and B states of a free-energy run input file. */
-
-void
-comp_trx(const gmx_output_env_t *oenv, const char *fn1, const char *fn2,
-         gmx_bool bRMSD, real ftol, real abstol);
-/* Compare two binary trajectory files */
-
-void
-comp_enx(const char *fn1, const char *fn2, real ftol, real abstol,
-         const char *lastener);
-/* Compare two binary energy files */
+void cmp_rvecs(FILE *fp, const char *title, int n, const rvec x1[], const rvec x2[],
+               gmx_bool bRMSD, real ftol, real abstol);
 
 #endif
index 2306951c07fee3d1616c95233463c1d56e04351b..b44e42f979a497ab2425d8596dbaaca39c773eac 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -140,14 +140,13 @@ void pr_ivecs(FILE *fp, int indent, const char *title, const ivec vec[], int n,
     }
 }
 
-void pr_rvec(FILE *fp, int indent, const char *title, const real vec[], int n, gmx_bool bShowNumbers)
+template <typename T>
+static void printRealVector(FILE *fp, int indent, const char *title, const T vec[], int n, gmx_bool bShowNumbers)
 {
-    int i;
-
     if (available(fp, vec, indent, title))
     {
         indent = pr_title_n(fp, indent, title, n);
-        for (i = 0; i < n; i++)
+        for (int i = 0; i < n; i++)
         {
             pr_indent(fp, indent);
             fprintf(fp, "%s[%d]=%12.5e\n", title, bShowNumbers ? i : -1, vec[i]);
@@ -155,19 +154,19 @@ void pr_rvec(FILE *fp, int indent, const char *title, const real vec[], int n, g
     }
 }
 
-void pr_dvec(FILE *fp, int indent, const char *title, const double vec[], int n, gmx_bool bShowNumbers)
+void pr_rvec(FILE *fp, int indent, const char *title, const real vec[], int n, gmx_bool bShowNumbers)
 {
-    int i;
+    printRealVector<real>(fp, indent, title, vec, n, bShowNumbers);
+}
 
-    if (available(fp, vec, indent, title))
-    {
-        indent = pr_title_n(fp, indent, title, n);
-        for (i = 0; i < n; i++)
-        {
-            pr_indent(fp, indent);
-            fprintf(fp, "%s[%d]=%12.5e\n", title, bShowNumbers ? i : -1, vec[i]);
-        }
-    }
+void pr_fvec(FILE *fp, int indent, const char *title, const float vec[], int n, gmx_bool bShowNumbers)
+{
+    printRealVector<float>(fp, indent, title, vec, n, bShowNumbers);
+}
+
+void pr_dvec(FILE *fp, int indent, const char *title, const double vec[], int n, gmx_bool bShowNumbers)
+{
+    printRealVector<double>(fp, indent, title, vec, n, bShowNumbers);
 }
 
 
index 4adb88bbb323e7ea8e09282ecfe2e6fa97339c6e..3c91d3f6a39f78d3567321dffa4ab23809651eaa 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -48,6 +48,7 @@ void pr_ivecs(FILE *fp, int indent, const char *title, const ivec vec[], int n,
 void pr_bvec(FILE *fp, int indent, const char *title, const gmx_bool vec[], int n, gmx_bool bShowNnumbers);
 void pr_rvec(FILE *fp, int indent, const char *title, const real vec[], int n, gmx_bool bShowNumbers);
 void pr_rvecs_of_dim(FILE *fp, int indent, const char *title, const rvec vec[], int n, int dim);
+void pr_fvec(FILE *fp, int indent, const char *title, const float vec[], int n, gmx_bool bShowNumbers);
 void pr_dvec(FILE *fp, int indent, const char *title, const double vec[], int n, gmx_bool bShowNumbers);
 void pr_rvecs(FILE *fp, int indent, const char *title, const rvec vec[], int n);
 void pr_rvecs_len(FILE *fp, int indent, const char *title, const rvec vec[], int n);
index 91b6d7c9a85102b32b8d75aaa86e8c2ca0ea7334..aac18fc4ea64f3286677c6dc31ab69bd3d3d86e8 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -54,8 +54,6 @@ typedef real    tensor[DIM][DIM];
 
 typedef int     ivec[DIM];
 
-typedef int     imatrix[DIM][DIM];
-
 #ifdef __cplusplus
 
 namespace gmx
index 6e9f04785c2244e6c209e34e9d622ed8c3f34c0d..876a8ea454208c73c2eda2c32855581bdec43c8f 100644 (file)
@@ -37,6 +37,8 @@
 /* This file is completely threadsafe - keep it that way! */
 #include "gmxpre.h"
 
+#include "broadcaststructs.h"
+
 #include <string.h>
 
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/smalloc.h"
 
-#define   block_bc(cr,   d) gmx_bcast(     sizeof(d),     &(d), (cr))
-/* Probably the test for (nr) > 0 in the next macro is only needed
- * on BlueGene(/L), where IBM's MPI_Bcast will segfault after
- * dereferencing a null pointer, even when no data is to be transferred. */
-#define  nblock_bc(cr, nr, d) { if ((nr) > 0) {gmx_bcast((nr)*sizeof((d)[0]), (d), (cr)); }}
-#define    snew_bc(cr, d, nr) { if (!MASTER(cr)) {snew((d), (nr)); }}
-/* Dirty macro with bAlloc not as an argument */
-#define nblock_abc(cr, nr, d) { if (bAlloc) {snew((d), (nr)); } nblock_bc(cr, (nr), (d)); }
-
 static void bc_cstring(const t_commrec *cr, char **s)
 {
     int size = 0;
@@ -262,10 +255,15 @@ static void bc_groups(const t_commrec *cr, t_symtab *symtab,
     }
 }
 
+static void bcastPaddedRVecVector(const t_commrec *cr, PaddedRVecVector *v, unsigned int n)
+{
+    (*v).resize(n + 1);
+    nblock_bc(cr, n, as_rvec_array(v->data()));
+}
+
 void bcast_state(const t_commrec *cr, t_state *state)
 {
     int      i, nnht, nnhtp;
-    gmx_bool bAlloc;
 
     if (!PAR(cr) || (cr->nnodes - cr->npmenodes <= 1))
     {
@@ -279,10 +277,7 @@ void bcast_state(const t_commrec *cr, t_state *state)
     block_bc(cr, state->nnhpres);
     block_bc(cr, state->nhchainlength);
     block_bc(cr, state->flags);
-    if (state->lambda == NULL)
-    {
-        snew_bc(cr, state->lambda, efptNR)
-    }
+    state->lambda.resize(efptNR);
 
     if (cr->dd)
     {
@@ -295,21 +290,13 @@ void bcast_state(const t_commrec *cr, t_state *state)
     nnht  = (state->ngtc)*(state->nhchainlength);
     nnhtp = (state->nnhpres)*(state->nhchainlength);
 
-    /* We still need to allocate the arrays in state for non-master
-     * ranks, which is done (implicitly via bAlloc) in the dirty,
-     * dirty nblock_abc macro. */
-    bAlloc = !MASTER(cr);
-    if (bAlloc)
-    {
-        state->nalloc = state->natoms;
-    }
     for (i = 0; i < estNR; i++)
     {
         if (state->flags & (1<<i))
         {
             switch (i)
             {
-                case estLAMBDA:  nblock_bc(cr, efptNR, state->lambda); break;
+                case estLAMBDA:  nblock_bc(cr, efptNR, state->lambda.data()); break;
                 case estFEPSTATE: block_bc(cr, state->fep_state); break;
                 case estBOX:     block_bc(cr, state->box); break;
                 case estBOX_REL: block_bc(cr, state->box_rel); break;
@@ -317,25 +304,25 @@ void bcast_state(const t_commrec *cr, t_state *state)
                 case estPRES_PREV: block_bc(cr, state->pres_prev); break;
                 case estSVIR_PREV: block_bc(cr, state->svir_prev); break;
                 case estFVIR_PREV: block_bc(cr, state->fvir_prev); break;
-                case estNH_XI:   nblock_abc(cr, nnht, state->nosehoover_xi); break;
-                case estNH_VXI:  nblock_abc(cr, nnht, state->nosehoover_vxi); break;
-                case estNHPRES_XI:   nblock_abc(cr, nnhtp, state->nhpres_xi); break;
-                case estNHPRES_VXI:  nblock_abc(cr, nnhtp, state->nhpres_vxi); break;
-                case estTC_INT:  nblock_abc(cr, state->ngtc, state->therm_integral); break;
+                case estNH_XI:   nblock_abc(cr, nnht, &state->nosehoover_xi); break;
+                case estNH_VXI:  nblock_abc(cr, nnht, &state->nosehoover_vxi); break;
+                case estNHPRES_XI:   nblock_abc(cr, nnhtp, &state->nhpres_xi); break;
+                case estNHPRES_VXI:  nblock_abc(cr, nnhtp, &state->nhpres_vxi); break;
+                case estTC_INT:  nblock_abc(cr, state->ngtc, &state->therm_integral); break;
                 case estVETA:    block_bc(cr, state->veta); break;
                 case estVOL0:    block_bc(cr, state->vol0); break;
-                case estX:       nblock_abc(cr, state->natoms, state->x); break;
-                case estV:       nblock_abc(cr, state->natoms, state->v); break;
-                case estCGP:     nblock_abc(cr, state->natoms, state->cg_p); break;
+                case estX:       bcastPaddedRVecVector(cr, &state->x, state->natoms);
+                case estV:       bcastPaddedRVecVector(cr, &state->v, state->natoms);
+                case estCGP:     bcastPaddedRVecVector(cr, &state->cg_p, state->natoms);
                 case estDISRE_INITF: block_bc(cr, state->hist.disre_initf); break;
                 case estDISRE_RM3TAV:
                     block_bc(cr, state->hist.ndisrepairs);
-                    nblock_abc(cr, state->hist.ndisrepairs, state->hist.disre_rm3tav);
+                    nblock_abc(cr, state->hist.ndisrepairs, &state->hist.disre_rm3tav);
                     break;
                 case estORIRE_INITF: block_bc(cr, state->hist.orire_initf); break;
                 case estORIRE_DTAV:
                     block_bc(cr, state->hist.norire_Dtav);
-                    nblock_abc(cr, state->hist.norire_Dtav, state->hist.orire_Dtav);
+                    nblock_abc(cr, state->hist.norire_Dtav, &state->hist.orire_Dtav);
                     break;
                 default:
                     gmx_fatal(FARGS,
@@ -493,18 +480,6 @@ static void bc_grpopts(const t_commrec *cr, t_grpopts *g)
     }
 }
 
-static void bc_cosines(const t_commrec *cr, t_cosines *cs)
-{
-    block_bc(cr, cs->n);
-    snew_bc(cr, cs->a, cs->n);
-    snew_bc(cr, cs->phi, cs->n);
-    if (cs->n > 0)
-    {
-        nblock_bc(cr, cs->n, cs->a);
-        nblock_bc(cr, cs->n, cs->phi);
-    }
-}
-
 static void bc_pull_group(const t_commrec *cr, t_pull_group *pgrp)
 {
     block_bc(cr, *pgrp);
@@ -687,9 +662,13 @@ static void bc_swapions(const t_commrec *cr, t_swapcoords *swap)
 
 static void bc_inputrec(const t_commrec *cr, t_inputrec *inputrec)
 {
-    int      i;
-
+    /* The statement below is dangerous. It overwrites all structures in inputrec.
+     * If something is added to inputrec, like efield it will need to be
+     * treated here.
+     */
+    gmx::IInputRecExtension *eptr = inputrec->efield;
     block_bc(cr, *inputrec);
+    inputrec->efield = eptr;
 
     bc_grpopts(cr, &(inputrec->opts));
 
@@ -727,11 +706,7 @@ static void bc_inputrec(const t_commrec *cr, t_inputrec *inputrec)
         snew_bc(cr, inputrec->imd, 1);
         bc_imd(cr, inputrec->imd);
     }
-    for (i = 0; (i < DIM); i++)
-    {
-        bc_cosines(cr, &(inputrec->ex[i]));
-        bc_cosines(cr, &(inputrec->et[i]));
-    }
+    inputrec->efield->broadCast(cr);
     if (inputrec->eSwapCoords != eswapNO)
     {
         snew_bc(cr, inputrec->swap, 1);
@@ -756,16 +731,12 @@ static void bc_moltype(const t_commrec *cr, t_symtab *symtab,
 
 static void bc_molblock(const t_commrec *cr, gmx_molblock_t *molb)
 {
-    block_bc(cr, molb->type);
-    block_bc(cr, molb->nmol);
-    block_bc(cr, molb->natoms_mol);
-    block_bc(cr, molb->nposres_xA);
+    block_bc(cr, *molb);
     if (molb->nposres_xA > 0)
     {
         snew_bc(cr, molb->posres_xA, molb->nposres_xA);
         nblock_bc(cr, molb->nposres_xA*DIM, molb->posres_xA[0]);
     }
-    block_bc(cr, molb->nposres_xB);
     if (molb->nposres_xB > 0)
     {
         snew_bc(cr, molb->posres_xB, molb->nposres_xB);
diff --git a/src/gromacs/mdlib/broadcaststructs.h b/src/gromacs/mdlib/broadcaststructs.h
new file mode 100644 (file)
index 0000000..fa5503e
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+
+/*! \libinternal \file
+ *
+ * \brief Convenience wrappers for broadcasting structs.
+ *
+ * \author Mark Abraham <mark.j.abraham@gmail.com>
+ *
+ * \inlibraryapi
+ * \ingroup module_mdlib
+ */
+#ifndef GMX_MDLIB_BROADCASTSTRUCTS_H
+#define GMX_MDLIB_BROADCASTSTRUCTS_H
+
+#include <vector>
+
+#include "gromacs/gmxlib/network.h"
+#include "gromacs/mdtypes/commrec.h"
+#include "gromacs/utility/smalloc.h"
+
+//! Convenience wrapper for gmx_bcast of a single value.
+template <typename T>
+void block_bc(const t_commrec *cr, T &data)
+{
+    gmx_bcast(sizeof(T), static_cast<void *>(&data), cr);
+}
+//! Convenience wrapper for gmx_bcast of a C-style array.
+template <typename T>
+void nblock_bc(const t_commrec *cr, int numElements, T *data)
+{
+    gmx_bcast(numElements * sizeof(T), static_cast<void *>(data), cr);
+}
+//! Convenience wrapper for allocation with snew of vectors that need allocation on non-master ranks.
+template <typename T>
+void snew_bc(const t_commrec *cr, T * &data, int numElements)
+{
+    if (!MASTER(cr))
+    {
+        snew(data, numElements);
+    }
+}
+//! Convenience wrapper for gmx_bcast of a C-style array which needs allocation on non-master ranks.
+template <typename T>
+static void nblock_abc(const t_commrec *cr, int numElements, T **v)
+{
+    snew_bc(cr, v, numElements);
+    nblock_bc(cr, numElements, *v);
+}
+//! Convenience wrapper for gmx_bcast of a std::vector which needs resizing on non-master ranks.
+template <typename T>
+static void nblock_abc(const t_commrec *cr, int numElements, std::vector<T> *v)
+{
+    if (!MASTER(cr))
+    {
+        v->resize(numElements);
+    }
+    gmx_bcast(numElements*sizeof(T), v->data(), cr);
+}
+
+#endif
index 8b9e70309bf2d098b28a440f54957923dd3654a7..630e19024807a3486ca7b839d16c73614b05e69f 100644 (file)
@@ -64,6 +64,7 @@
 #include "gromacs/pulling/pull.h"
 #include "gromacs/topology/block.h"
 #include "gromacs/topology/invblock.h"
+#include "gromacs/topology/mtop_lookup.h"
 #include "gromacs/topology/mtop_util.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fatalerror.h"
@@ -183,7 +184,7 @@ static void write_constr_pdb(const char *fn, const char *title,
     FILE         *out;
     int           dd_ac0 = 0, dd_ac1 = 0, i, ii, resnr;
     gmx_domdec_t *dd;
-    char         *anm, *resnm;
+    const char   *anm, *resnm;
 
     dd = NULL;
     if (DOMAINDECOMP(cr))
@@ -207,6 +208,7 @@ static void write_constr_pdb(const char *fn, const char *title,
 
     fprintf(out, "TITLE     %s\n", title);
     gmx_write_pdb_box(out, -1, box);
+    int molb = 0;
     for (i = start; i < start+homenr; i++)
     {
         if (dd != NULL)
@@ -221,7 +223,7 @@ static void write_constr_pdb(const char *fn, const char *title,
         {
             ii = i;
         }
-        gmx_mtop_atominfo_global(mtop, ii, &anm, &resnr, &resnm);
+        mtopGetAtomAndResidueName(mtop, ii, &molb, &anm, &resnr, &resnm, nullptr);
         gmx_fprintf_pdb_atomline(out, epdbATOM, ii+1, anm, ' ', resnm, ' ', resnr, ' ',
                                  10*x[i][XX], 10*x[i][YY], 10*x[i][ZZ], 1.0, 0.0, "");
     }
@@ -1300,9 +1302,9 @@ gmx_constr_t init_constraints(FILE *fplog,
     /* Initialize the essential dynamics sampling.
      * Put the pointer to the ED struct in constr */
     constr->ed = ed;
-    if (ed != NULL || state->edsamstate.nED > 0)
+    if (ed != NULL || state->edsamstate != NULL)
     {
-        init_edsam(mtop, ir, cr, ed, state->x, state->box, &state->edsamstate);
+        init_edsam(mtop, ir, cr, ed, as_rvec_array(state->x.data()), state->box, state->edsamstate);
     }
 
     constr->warn_mtop = mtop;
index 50c9a1b463fbc85c60d0ed59f4c9475f1ba1bdfb..b3f8657c08ce08fb6e7e89c9b8a3ec4f9d075369 100644 (file)
@@ -118,6 +118,8 @@ gmx_bool bshakef(FILE           *log,          /* Log file                  */
 gmx_settledata_t settle_init(const gmx_mtop_t *mtop);
 /* Initializes and returns a structure with SETTLE parameters */
 
+void settle_free(gmx_settledata_t settled);
+
 void settle_set_constraints(gmx_settledata_t  settled,
                             const t_ilist    *il_settle,
                             const t_mdatoms  *mdatoms);
index abafb2b8b050576fceadd4c939dbdae57904b9ff..970b53a21d9aded3ad336f399eca8e6dad2fdc81 100644 (file)
@@ -343,7 +343,7 @@ real calc_temp(real ekin, real nrdf)
 }
 
 void parrinellorahman_pcoupl(FILE *fplog, gmx_int64_t step,
-                             t_inputrec *ir, real dt, tensor pres,
+                             const t_inputrec *ir, real dt, const tensor pres,
                              tensor box, tensor box_rel, tensor boxv,
                              tensor M, matrix mu, gmx_bool bFirstStep)
 {
@@ -541,7 +541,8 @@ void parrinellorahman_pcoupl(FILE *fplog, gmx_int64_t step,
 }
 
 void berendsen_pcoupl(FILE *fplog, gmx_int64_t step,
-                      t_inputrec *ir, real dt, tensor pres, matrix box,
+                      const t_inputrec *ir, real dt,
+                      const tensor pres, const matrix box,
                       matrix mu)
 {
     int     d, n;
@@ -652,10 +653,10 @@ void berendsen_pcoupl(FILE *fplog, gmx_int64_t step,
     }
 }
 
-void berendsen_pscale(t_inputrec *ir, matrix mu,
+void berendsen_pscale(const t_inputrec *ir, const matrix mu,
                       matrix box, matrix box_rel,
                       int start, int nr_atoms,
-                      rvec x[], unsigned short cFREEZE[],
+                      rvec x[], const unsigned short cFREEZE[],
                       t_nrnb *nrnb)
 {
     ivec   *nFreeze = ir->opts.nFreeze;
@@ -822,32 +823,6 @@ void nosehoover_tcoupl(t_grpopts *opts, gmx_ekindata_t *ekind, real dt,
     }
 }
 
-t_state *init_bufstate(const t_state *template_state)
-{
-    t_state *state;
-    int      nc = template_state->nhchainlength;
-    snew(state, 1);
-    snew(state->nosehoover_xi, nc*template_state->ngtc);
-    snew(state->nosehoover_vxi, nc*template_state->ngtc);
-    snew(state->therm_integral, template_state->ngtc);
-    snew(state->nhpres_xi, nc*template_state->nnhpres);
-    snew(state->nhpres_vxi, nc*template_state->nnhpres);
-
-    return state;
-}
-
-void destroy_bufstate(t_state *state)
-{
-    sfree(state->x);
-    sfree(state->v);
-    sfree(state->nosehoover_xi);
-    sfree(state->nosehoover_vxi);
-    sfree(state->therm_integral);
-    sfree(state->nhpres_xi);
-    sfree(state->nhpres_vxi);
-    sfree(state);
-}
-
 void trotter_update(t_inputrec *ir, gmx_int64_t step, gmx_ekindata_t *ekind,
                     gmx_enerdata_t *enerd, t_state *state,
                     tensor vir, t_mdatoms *md,
@@ -917,13 +892,13 @@ void trotter_update(t_inputrec *ir, gmx_int64_t step, gmx_ekindata_t *ekind,
                 break;
             case etrtBARONHC:
             case etrtBARONHC2:
-                NHC_trotter(opts, state->nnhpres, ekind, dt, state->nhpres_xi,
-                            state->nhpres_vxi, NULL, &(state->veta), MassQ, FALSE);
+                NHC_trotter(opts, state->nnhpres, ekind, dt, state->nhpres_xi.data(),
+                            state->nhpres_vxi.data(), NULL, &(state->veta), MassQ, FALSE);
                 break;
             case etrtNHC:
             case etrtNHC2:
-                NHC_trotter(opts, opts->ngtc, ekind, dt, state->nosehoover_xi,
-                            state->nosehoover_vxi, scalefac, NULL, MassQ, (ir->eI == eiVV));
+                NHC_trotter(opts, opts->ngtc, ekind, dt, state->nosehoover_xi.data(),
+                            state->nosehoover_vxi.data(), scalefac, NULL, MassQ, (ir->eI == eiVV));
                 /* need to rescale the kinetic energies and velocities here.  Could
                    scale the velocities later, but we need them scaled in order to
                    produce the correct outputs, so we'll scale them here. */
@@ -1264,124 +1239,158 @@ int **init_npt_vars(t_inputrec *ir, t_state *state, t_extmass *MassQ, gmx_bool b
     return trotter_seq;
 }
 
-real NPT_energy(t_inputrec *ir, t_state *state, t_extmass *MassQ)
+static real energyNoseHoover(const t_inputrec *ir, const t_state *state, const t_extmass *MassQ)
 {
-    int     i, j;
-    real    nd, ndj;
-    real    ener_npt, reft, kT;
-    double *ivxi, *ixi;
-    double *iQinv;
-    real    vol;
-    int     nh = state->nhchainlength;
+    real energy = 0;
 
-    ener_npt = 0;
+    int  nh     = state->nhchainlength;
 
-    /* now we compute the contribution of the pressure to the conserved quantity*/
-
-    if (ir->epc == epcMTTK)
+    for (int i = 0; i < ir->opts.ngtc; i++)
     {
-        /* find the volume, and the kinetic energy of the volume */
-
-        switch (ir->epct)
-        {
+        const double *ixi   = &state->nosehoover_xi[i*nh];
+        const double *ivxi  = &state->nosehoover_vxi[i*nh];
+        const double *iQinv = &(MassQ->Qinv[i*nh]);
 
-            case epctISOTROPIC:
-                /* contribution from the pressure momenenta */
-                ener_npt += 0.5*gmx::square(state->veta)/MassQ->Winv;
+        int           nd    = ir->opts.nrdf[i];
+        real          reft  = std::max<real>(ir->opts.ref_t[i], 0);
+        real          kT    = BOLTZ * reft;
 
-                /* contribution from the PV term */
-                vol       = det(state->box);
-                ener_npt += vol*trace(ir->ref_p)/(DIM*PRESFAC);
+        if (nd > 0.0)
+        {
+            if (inputrecNvtTrotter(ir))
+            {
+                /* contribution from the thermal momenta of the NH chain */
+                for (int j = 0; j < nh; j++)
+                {
+                    if (iQinv[j] > 0)
+                    {
+                        energy += 0.5*gmx::square(ivxi[j])/iQinv[j];
+                        /* contribution from the thermal variable of the NH chain */
+                        int ndj;
+                        if (j == 0)
+                        {
+                            ndj = nd;
+                        }
+                        else
+                        {
+                            ndj = 1.0;
+                        }
+                        energy += ndj*ixi[j]*kT;
+                    }
+                }
+            }
+            else  /* Other non Trotter temperature NH control  -- no chains yet. */
+            {
+                energy += 0.5*BOLTZ*nd*gmx::square(ivxi[0])/iQinv[0];
+                energy += nd*ixi[0]*kT;
+            }
+        }
+    }
 
-                break;
-            case epctANISOTROPIC:
+    return energy;
+}
 
-                break;
+/* Returns the energy from the barostat thermostat chain */
+static real energyPressureMTTK(const t_inputrec *ir, const t_state *state, const t_extmass *MassQ)
+{
+    real energy = 0;
 
-            case epctSURFACETENSION:
+    int  nh     = state->nhchainlength;
 
-                break;
-            case epctSEMIISOTROPIC:
+    for (int i = 0; i < state->nnhpres; i++)
+    {
+        /* note -- assumes only one degree of freedom that is thermostatted in barostat */
+        real    reft  = std::max<real>(ir->opts.ref_t[0], 0.0); /* using 'System' temperature */
+        real    kT    = BOLTZ * reft;
 
-                break;
-            default:
-                break;
+        for (int j = 0; j < nh; j++)
+        {
+            double iQinv = MassQ->QPinv[i*nh + j];
+            if (iQinv > 0)
+            {
+                energy += 0.5*gmx::square(state->nhpres_vxi[i*nh + j]/iQinv);
+                /* contribution from the thermal variable of the NH chain */
+                energy += state->nhpres_xi[i*nh + j]*kT;
+            }
+            if (debug)
+            {
+                fprintf(debug, "P-T-group: %10d Chain %4d ThermV: %15.8f ThermX: %15.8f", i, j, state->nhpres_vxi[i*nh + j], state->nhpres_xi[i*nh + j]);
+            }
         }
     }
 
-    if (inputrecNptTrotter(ir) || inputrecNphTrotter(ir))
+    return energy;
+}
+
+/* Returns the energy accumulated by the V-rescale or Berendsen thermostat */
+static real energyVrescale(const t_inputrec *ir, const t_state *state)
+{
+    real energy = 0;
+    for (int i = 0; i < ir->opts.ngtc; i++)
     {
-        /* add the energy from the barostat thermostat chain */
-        for (i = 0; i < state->nnhpres; i++)
-        {
+        energy += state->therm_integral[i];
+    }
 
-            /* note -- assumes only one degree of freedom that is thermostatted in barostat */
-            ivxi  = &state->nhpres_vxi[i*nh];
-            ixi   = &state->nhpres_xi[i*nh];
-            iQinv = &(MassQ->QPinv[i*nh]);
-            reft  = std::max<real>(ir->opts.ref_t[0], 0.0); /* using 'System' temperature */
-            kT    = BOLTZ * reft;
+    return energy;
+}
 
-            for (j = 0; j < nh; j++)
-            {
-                if (iQinv[j] > 0)
-                {
-                    ener_npt += 0.5*gmx::square(ivxi[j])/iQinv[j];
-                    /* contribution from the thermal variable of the NH chain */
-                    ener_npt += ixi[j]*kT;
-                }
-                if (debug)
-                {
-                    fprintf(debug, "P-T-group: %10d Chain %4d ThermV: %15.8f ThermX: %15.8f", i, j, ivxi[j], ixi[j]);
-                }
-            }
-        }
-    }
+real NPT_energy(const t_inputrec *ir, const t_state *state, const t_extmass *MassQ)
+{
+    real energyNPT = 0;
 
-    if (ir->etc)
+    if (ir->epc != epcNO)
     {
-        for (i = 0; i < ir->opts.ngtc; i++)
+        /* Compute the contribution of the pressure to the conserved quantity*/
+
+        real vol  = det(state->box);
+
+        switch (ir->epc)
         {
-            ixi   = &state->nosehoover_xi[i*nh];
-            ivxi  = &state->nosehoover_vxi[i*nh];
-            iQinv = &(MassQ->Qinv[i*nh]);
+            case epcPARRINELLORAHMAN:
+                // TODO: Implement
+                break;
+            case epcMTTK:
+                /* contribution from the pressure momenta */
+                energyNPT += 0.5*gmx::square(state->veta)/MassQ->Winv;
 
-            nd   = ir->opts.nrdf[i];
-            reft = std::max<real>(ir->opts.ref_t[i], 0);
-            kT   = BOLTZ * reft;
+                /* contribution from the PV term */
+                energyNPT += vol*trace(ir->ref_p)/(DIM*PRESFAC);
 
-            if (nd > 0.0)
-            {
-                if (inputrecNvtTrotter(ir))
-                {
-                    /* contribution from the thermal momenta of the NH chain */
-                    for (j = 0; j < nh; j++)
-                    {
-                        if (iQinv[j] > 0)
-                        {
-                            ener_npt += 0.5*gmx::square(ivxi[j])/iQinv[j];
-                            /* contribution from the thermal variable of the NH chain */
-                            if (j == 0)
-                            {
-                                ndj = nd;
-                            }
-                            else
-                            {
-                                ndj = 1.0;
-                            }
-                            ener_npt += ndj*ixi[j]*kT;
-                        }
-                    }
-                }
-                else  /* Other non Trotter temperature NH control  -- no chains yet. */
+                if (ir->epc == epcMTTK)
                 {
-                    ener_npt += 0.5*BOLTZ*nd*gmx::square(ivxi[0])/iQinv[0];
-                    ener_npt += nd*ixi[0]*kT;
+                    /* contribution from the MTTK chain */
+                    energyNPT += energyPressureMTTK(ir, state, MassQ);
                 }
-            }
+                break;
+            case epcBERENDSEN:
+                // Not supported, excluded in integratorHasConservedEnergyQuantity()
+                // TODO: Implement
+                break;
+            default:
+                GMX_RELEASE_ASSERT(false, "Conserved energy quantity for pressure coupling is not handled. A case should be added with either the conserved quantity added or nothing added and an exclusion added to integratorHasConservedEnergyQuantity().");
         }
     }
-    return ener_npt;
+
+    switch (ir->etc)
+    {
+        case etcNO:
+            break;
+        case etcVRESCALE:
+        case etcBERENDSEN:
+            energyNPT += energyVrescale(ir, state);
+            break;
+        case etcNOSEHOOVER:
+            energyNPT += energyNoseHoover(ir, state, MassQ);
+            break;
+        case etcANDERSEN:
+        case etcANDERSENMASSIVE:
+            // Not supported, excluded in integratorHasConservedEnergyQuantity()
+            break;
+        default:
+            GMX_RELEASE_ASSERT(false, "Conserved energy quantity for temperature coupling is not handled. A case should be added with either the conserved quantity added or nothing added and an exclusion added to integratorHasConservedEnergyQuantity().");
+    }
+
+    return energyNPT;
 }
 
 
@@ -1517,20 +1526,6 @@ void vrescale_tcoupl(t_inputrec *ir, gmx_int64_t step,
     }
 }
 
-real vrescale_energy(t_grpopts *opts, double therm_integral[])
-{
-    int  i;
-    real ener;
-
-    ener = 0;
-    for (i = 0; i < opts->ngtc; i++)
-    {
-        ener += therm_integral[i];
-    }
-
-    return ener;
-}
-
 void rescale_velocities(gmx_ekindata_t *ekind, t_mdatoms *mdatoms,
                         int start, int end, rvec v[])
 {
index 092ee94ac94b6eca9922bc0bafcddd167f7c6a9f..74e9d498c3722ad6350ba6f0175a5b82289b1bf7 100644 (file)
@@ -94,44 +94,43 @@ typedef struct gmx_settledata
 } t_gmx_settledata;
 
 
-static void init_proj_matrix(settleparam_t *p,
-                             real invmO, real invmH, real dOH, real dHH)
+static void init_proj_matrix(real invmO, real invmH, real dOH, real dHH,
+                             matrix inverseCouplingMatrix)
 {
-    real   imOn, imHn;
-    matrix mat;
-
-    p->imO = invmO;
-    p->imH = invmH;
-    /* We normalize the inverse masses with imO for the matrix inversion.
+    /* We normalize the inverse masses with invmO for the matrix inversion.
      * so we can keep using masses of almost zero for frozen particles,
      * without running out of the float range in invertMatrix.
      */
-    imOn = 1;
-    imHn = p->imH/p->imO;
+    double invmORelative = 1.0;
+    double invmHRelative = invmH/static_cast<double>(invmO);
+    double distanceRatio = dHH/static_cast<double>(dOH);
 
     /* Construct the constraint coupling matrix */
-    mat[0][0] = imOn + imHn;
-    mat[0][1] = imOn*(1 - 0.5*dHH*dHH/(dOH*dOH));
-    mat[0][2] = imHn*0.5*dHH/dOH;
+    matrix mat;
+    mat[0][0] = invmORelative + invmHRelative;
+    mat[0][1] = invmORelative*(1.0 - 0.5*gmx::square(distanceRatio));
+    mat[0][2] = invmHRelative*0.5*distanceRatio;
     mat[1][1] = mat[0][0];
     mat[1][2] = mat[0][2];
-    mat[2][2] = imHn + imHn;
+    mat[2][2] = invmHRelative + invmHRelative;
     mat[1][0] = mat[0][1];
     mat[2][0] = mat[0][2];
     mat[2][1] = mat[1][2];
 
-    gmx::invertMatrix(mat, p->invmat);
+    invertMatrix(mat, inverseCouplingMatrix);
 
-    msmul(p->invmat, 1/p->imO, p->invmat);
-
-    p->invdOH = 1/dOH;
-    p->invdHH = 1/dHH;
+    msmul(inverseCouplingMatrix, 1/invmO, inverseCouplingMatrix);
 }
 
 static void settleparam_init(settleparam_t *p,
                              real mO, real mH, real invmO, real invmH,
                              real dOH, real dHH)
 {
+    /* We calculate parameters in double precision to minimize errors.
+     * The velocity correction applied during SETTLE coordinate constraining
+     * introduces a systematic error of approximately 1 bit per atom,
+     * depending on what the compiler does with the code.
+     */
     double wohh;
 
     p->mO     = mO;
@@ -140,13 +139,21 @@ static void settleparam_init(settleparam_t *p,
     p->wh     = mH/wohh;
     p->dOH    = dOH;
     p->dHH    = dHH;
-    p->rc     = dHH/2.0;
-    p->ra     = 2.0*mH*sqrt(dOH*dOH - p->rc*p->rc)/wohh;
-    p->rb     = sqrt(dOH*dOH - p->rc*p->rc) - p->ra;
+    double rc = dHH/2.0;
+    double ra = 2.0*mH*std::sqrt(dOH*dOH - rc*rc)/wohh;
+    p->rb     = std::sqrt(dOH*dOH - rc*rc) - ra;
+    p->rc     = rc;
+    p->ra     = ra;
     p->irc2   = 1.0/dHH;
 
-    /* For projection: connection matrix inversion */
-    init_proj_matrix(p, invmO, invmH, dOH, dHH);
+    /* For projection: inverse masses and coupling matrix inversion */
+    p->imO    = invmO;
+    p->imH    = invmH;
+
+    p->invdOH = 1.0/dOH;
+    p->invdHH = 1.0/dHH;
+
+    init_proj_matrix(invmO, invmH, dOH, dHH, p->invmat);
 
     if (debug)
     {
@@ -213,6 +220,15 @@ gmx_settledata_t settle_init(const gmx_mtop_t *mtop)
     return settled;
 }
 
+void settle_free(gmx_settledata_t settled)
+{
+    sfree_aligned(settled->ow1);
+    sfree_aligned(settled->hw2);
+    sfree_aligned(settled->hw3);
+    sfree_aligned(settled->virfac);
+    sfree(settled);
+}
+
 void settle_set_constraints(gmx_settledata_t  settled,
                             const t_ilist    *il_settle,
                             const t_mdatoms  *mdatoms)
index fa592e1993b0a7736fe2c524975858c6f2c0bf29..238b5e160b121e02aa7cbf867d6852b12269fec8 100644 (file)
@@ -459,7 +459,8 @@ void do_force_lowlevel(t_forcerec *fr,      t_inputrec *ir,
                                            excl, x, bSB ? boxs : box, mu_tot,
                                            ir->ewald_geometry,
                                            ir->epsilon_surface,
-                                           fr->f_novirsum, *vir_q, *vir_lj,
+                                           as_rvec_array(fr->f_novirsum->data()),
+                                           *vir_q, *vir_lj,
                                            Vcorrt_q, Vcorrt_lj,
                                            lambda[efptCOUL], lambda[efptVDW],
                                            dvdlt_q, dvdlt_lj);
@@ -496,14 +497,7 @@ void do_force_lowlevel(t_forcerec *fr,      t_inputrec *ir,
                 if (fr->n_tpi == 0 || (flags & GMX_FORCE_STATECHANGED))
                 {
                     pme_flags = GMX_PME_SPREAD | GMX_PME_SOLVE;
-                    if (EEL_PME(fr->eeltype))
-                    {
-                        pme_flags     |= GMX_PME_DO_COULOMB;
-                    }
-                    if (EVDW_PME(fr->vdwtype))
-                    {
-                        pme_flags |= GMX_PME_DO_LJ;
-                    }
+
                     if (flags & GMX_FORCE_FORCES)
                     {
                         pme_flags |= GMX_PME_CALC_F;
@@ -520,7 +514,8 @@ void do_force_lowlevel(t_forcerec *fr,      t_inputrec *ir,
                     wallcycle_start(wcycle, ewcPMEMESH);
                     status = gmx_pme_do(fr->pmedata,
                                         0, md->homenr - fr->n_tpi,
-                                        x, fr->f_novirsum,
+                                        x,
+                                        as_rvec_array(fr->f_novirsum->data()),
                                         md->chargeA, md->chargeB,
                                         md->sqrt_c6A, md->sqrt_c6B,
                                         md->sigmaA, md->sigmaB,
@@ -528,8 +523,7 @@ void do_force_lowlevel(t_forcerec *fr,      t_inputrec *ir,
                                         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_q,
-                                        fr->vir_lj_recip, fr->ewaldcoeff_lj,
+                                        fr->vir_el_recip, fr->vir_lj_recip,
                                         &Vlr_q, &Vlr_lj,
                                         lambda[efptCOUL], lambda[efptVDW],
                                         &dvdl_long_range_q, &dvdl_long_range_lj, pme_flags);
@@ -566,7 +560,7 @@ void do_force_lowlevel(t_forcerec *fr,      t_inputrec *ir,
 
         if (!EEL_PME(fr->eeltype) && EEL_PME_EWALD(fr->eeltype))
         {
-            Vlr_q = do_ewald(ir, x, fr->f_novirsum,
+            Vlr_q = do_ewald(ir, x, as_rvec_array(fr->f_novirsum->data()),
                              md->chargeA, md->chargeB,
                              box_size, cr, md->homenr,
                              fr->vir_el_recip, fr->ewaldcoeff_q,
@@ -740,7 +734,7 @@ void sum_epot(gmx_grppairener_t *grpp, real *epot)
     }
 }
 
-void sum_dhdl(gmx_enerdata_t *enerd, real *lambda, t_lambda *fepvals)
+void sum_dhdl(gmx_enerdata_t *enerd, const std::vector<real> *lambda, t_lambda *fepvals)
 {
     int    i, j, index;
     double dlam;
@@ -822,7 +816,7 @@ void sum_dhdl(gmx_enerdata_t *enerd, real *lambda, t_lambda *fepvals)
         for (j = 0; j < efptNR; j++)
         {
             /* Note that this loop is over all dhdl components, not just the separated ones */
-            dlam = (fepvals->all_lambda[j][i]-lambda[j]);
+            dlam = (fepvals->all_lambda[j][i] - (*lambda)[j]);
             enerd->enerpart_lambda[i+1] += dlam*enerd->dvdl_lin[j];
             if (debug)
             {
index 3fe505cf0b4f3397ac061371fdc115d1a1b5d8fb..704561c4642f05875e7afe15dfc4c78a4b0035bc 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -41,6 +41,7 @@
 #include "gromacs/mdlib/vsite.h"
 #include "gromacs/mdtypes/fcdata.h"
 #include "gromacs/mdtypes/forcerec.h"
+#include "gromacs/mdtypes/state.h"
 #include "gromacs/timing/wallcycle.h"
 
 struct gmx_edsam;
@@ -60,6 +61,11 @@ struct t_mdatoms;
 struct t_nrnb;
 struct t_pbc;
 
+namespace gmx
+{
+class MDLogger;
+}
+
 void calc_vir(int nxf, rvec x[], rvec f[], tensor vir,
               gmx_bool bScrewPBC, matrix box);
 /* Calculate virial for nxf atoms, and add it to vir */
@@ -106,19 +112,17 @@ gmx_bool can_use_allvsall(const t_inputrec *ir,
  */
 
 
-gmx_bool nbnxn_gpu_acceleration_supported(FILE             *fplog,
-                                          const t_commrec  *cr,
-                                          const t_inputrec *ir,
-                                          gmx_bool          bRerunMD);
+gmx_bool nbnxn_gpu_acceleration_supported(const gmx::MDLogger &mdlog,
+                                          const t_inputrec    *ir,
+                                          gmx_bool             bRerunMD);
 /* Return if GPU acceleration is supported with the given settings.
  *
  * If the return value is FALSE and fplog/cr != NULL, prints a fallback
  * message to fplog/stderr.
  */
 
-gmx_bool nbnxn_simd_supported(FILE             *fplog,
-                              const t_commrec  *cr,
-                              const t_inputrec *ir);
+gmx_bool nbnxn_simd_supported(const gmx::MDLogger &mdlog,
+                              const t_inputrec    *ir);
 /* Return if CPU SIMD support exists for the given inputrec
  * If the return value is FALSE and fplog/cr != NULL, prints a fallback
  * message to fplog/stderr.
@@ -146,7 +150,7 @@ void reset_enerdata(gmx_enerdata_t *enerd);
 void sum_epot(gmx_grppairener_t *grpp, real *epot);
 /* Locally sum the non-bonded potential energy terms */
 
-void sum_dhdl(gmx_enerdata_t *enerd, real *lambda, t_lambda *fepvals);
+void sum_dhdl(gmx_enerdata_t *enerd, const std::vector<real> *lambda, t_lambda *fepvals);
 /* Sum the free energy contributions */
 
 /* Compute the average C6 and C12 params for LJ corrections */
@@ -158,15 +162,15 @@ void do_force(FILE *log, t_commrec *cr,
               gmx_int64_t step, struct t_nrnb *nrnb, gmx_wallcycle_t wcycle,
               gmx_localtop_t *top,
               gmx_groups_t *groups,
-              matrix box, rvec x[], history_t *hist,
-              rvec f[],
+              matrix box, PaddedRVecVector *coordinates, history_t *hist,
+              PaddedRVecVector *force,
               tensor vir_force,
               t_mdatoms *mdatoms,
               gmx_enerdata_t *enerd, t_fcdata *fcd,
-              real *lambda, struct t_graph *graph,
+              std::vector<real> *lambda, struct t_graph *graph,
               t_forcerec *fr,
               gmx_vsite_t *vsite, rvec mu_tot,
-              double t, FILE *field, struct gmx_edsam *ed,
+              double t, struct gmx_edsam *ed,
               gmx_bool bBornRadii,
               int flags);
 
index 6b5a102f83a2f9adc68960e8b672e1c253384ca1..ae662ec467d8eb5e97ba585f84d3fa04ec830cc2 100644 (file)
@@ -53,7 +53,6 @@
 #include "gromacs/domdec/domdec_struct.h"
 #include "gromacs/ewald/ewald.h"
 #include "gromacs/fileio/filetypes.h"
-#include "gromacs/gmxlib/md_logging.h"
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/gmxlib/nonbonded/nonbonded.h"
 #include "gromacs/gpu_utils/gpu_utils.h"
@@ -93,6 +92,7 @@
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/logger.h"
 #include "gromacs/utility/pleasecite.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/stringutil.h"
@@ -1504,16 +1504,8 @@ void forcerec_set_ranges(t_forcerec *fr,
 
     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;
+        /* TODO: remove this + 1 when padding is properly implemented */
+        fr->forceBufferNoVirialSummation->resize(natoms_f_novirsum + 1);
     }
 }
 
@@ -1553,10 +1545,6 @@ gmx_bool can_use_allvsall(const t_inputrec *ir, gmx_bool bPrintNote, t_commrec *
 
         if (bPrintNote)
         {
-            if (MASTER(cr))
-            {
-                fprintf(stderr, "\n%s\n", note);
-            }
             if (fp != NULL)
             {
                 fprintf(fp, "\n%s\n", note);
@@ -1574,10 +1562,9 @@ gmx_bool can_use_allvsall(const t_inputrec *ir, gmx_bool bPrintNote, t_commrec *
 }
 
 
-gmx_bool nbnxn_gpu_acceleration_supported(FILE             *fplog,
-                                          const t_commrec  *cr,
-                                          const t_inputrec *ir,
-                                          gmx_bool          bRerunMD)
+gmx_bool nbnxn_gpu_acceleration_supported(const gmx::MDLogger &mdlog,
+                                          const t_inputrec    *ir,
+                                          gmx_bool             bRerunMD)
 {
     if (bRerunMD && ir->opts.ngener > 1)
     {
@@ -1589,23 +1576,22 @@ gmx_bool nbnxn_gpu_acceleration_supported(FILE             *fplog,
          * (which runs much faster than a multiple-energy-groups
          * implementation would), and issue a note in the .log
          * file. Users can re-run if they want the information. */
-        md_print_warn(cr, fplog, "Rerun with energy groups is not implemented for GPUs, falling back to the CPU\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText("Rerun with energy groups is not implemented for GPUs, falling back to the CPU");
         return FALSE;
     }
 
     return TRUE;
 }
 
-gmx_bool nbnxn_simd_supported(FILE             *fplog,
-                              const t_commrec  *cr,
-                              const t_inputrec *ir)
+gmx_bool nbnxn_simd_supported(const gmx::MDLogger &mdlog,
+                              const t_inputrec    *ir)
 {
     if (ir->vdwtype == evdwPME && ir->ljpme_combination_rule == eljpmeLB)
     {
         /* LJ PME with LB combination rule does 7 mesh operations.
          * This so slow that we don't compile SIMD non-bonded kernels
          * for that. */
-        md_print_warn(cr, fplog, "LJ-PME with Lorentz-Berthelot is not supported with SIMD kernels, falling back to plain C kernels\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText("LJ-PME with Lorentz-Berthelot is not supported with SIMD kernels, falling back to plain C kernels");
         return FALSE;
     }
 
@@ -1736,7 +1722,7 @@ const char *lookup_nbnxn_kernel_name(int kernel_type)
 };
 
 static void pick_nbnxn_kernel(FILE                *fp,
-                              const t_commrec     *cr,
+                              const gmx::MDLogger &mdlog,
                               gmx_bool             use_simd_kernels,
                               gmx_bool             bUseGPU,
                               gmx_bool             bEmulateGPU,
@@ -1756,7 +1742,7 @@ static void pick_nbnxn_kernel(FILE                *fp,
 
         if (bDoNonbonded)
         {
-            md_print_warn(cr, fp, "Emulating a GPU run on the CPU (slow)");
+            GMX_LOG(mdlog.warning).asParagraph().appendText("Emulating a GPU run on the CPU (slow)");
         }
     }
     else if (bUseGPU)
@@ -1767,7 +1753,7 @@ static void pick_nbnxn_kernel(FILE                *fp,
     if (*kernel_type == nbnxnkNotSet)
     {
         if (use_simd_kernels &&
-            nbnxn_simd_supported(fp, cr, ir))
+            nbnxn_simd_supported(mdlog, ir))
         {
             pick_nbnxn_kernel_cpu(ir, kernel_type, ewald_excl);
         }
@@ -1787,15 +1773,15 @@ static void pick_nbnxn_kernel(FILE                *fp,
         if (nbnxnk4x4_PlainC == *kernel_type ||
             nbnxnk8x8x8_PlainC == *kernel_type)
         {
-            md_print_warn(cr, fp,
-                          "WARNING: Using the slow %s kernels. This should\n"
-                          "not happen during routine usage on supported platforms.\n\n",
-                          lookup_nbnxn_kernel_name(*kernel_type));
+            GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                    "WARNING: Using the slow %s kernels. This should\n"
+                    "not happen during routine usage on supported platforms.",
+                    lookup_nbnxn_kernel_name(*kernel_type));
         }
     }
 }
 
-static void pick_nbnxn_resources(FILE                *fp,
+static void pick_nbnxn_resources(const gmx::MDLogger &mdlog,
                                  const t_commrec     *cr,
                                  const gmx_hw_info_t *hwinfo,
                                  gmx_bool             bDoNonbonded,
@@ -1830,7 +1816,7 @@ static void pick_nbnxn_resources(FILE                *fp,
     {
         /* Each PP node will use the intra-node id-th device from the
          * list of detected/selected GPUs. */
-        if (!init_gpu(fp, cr->rank_pp_intranode, gpu_err_str,
+        if (!init_gpu(mdlog, cr->rank_pp_intranode, gpu_err_str,
                       &hwinfo->gpu_info, gpu_opt))
         {
             /* At this point the init should never fail as we made sure that
@@ -2114,6 +2100,7 @@ init_interaction_const(FILE                       *fp,
 }
 
 static void init_nb_verlet(FILE                *fp,
+                           const gmx::MDLogger &mdlog,
                            nonbonded_verlet_t **nb_verlet,
                            gmx_bool             bFEP_NonBonded,
                            const t_inputrec    *ir,
@@ -2131,7 +2118,7 @@ static void init_nb_verlet(FILE                *fp,
 
     snew(nbv, 1);
 
-    pick_nbnxn_resources(fp, cr, fr->hwinfo,
+    pick_nbnxn_resources(mdlog, cr, fr->hwinfo,
                          fr->bNonbonded,
                          &nbv->bUseGPU,
                          &bEmulateGPU,
@@ -2149,7 +2136,7 @@ static void init_nb_verlet(FILE                *fp,
 
         if (i == 0) /* local */
         {
-            pick_nbnxn_kernel(fp, cr, fr->use_simd_kernels,
+            pick_nbnxn_kernel(fp, mdlog, fr->use_simd_kernels,
                               nbv->bUseGPU, bEmulateGPU, ir,
                               &nbv->grp[i].kernel_type,
                               &nbv->grp[i].ewald_excl,
@@ -2160,7 +2147,7 @@ static void init_nb_verlet(FILE                *fp,
             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->use_simd_kernels,
+                pick_nbnxn_kernel(fp, mdlog, fr->use_simd_kernels,
                                   FALSE, FALSE, ir,
                                   &nbv->grp[i].kernel_type,
                                   &nbv->grp[i].ewald_excl,
@@ -2313,19 +2300,20 @@ gmx_bool usingGpu(nonbonded_verlet_t *nbv)
     return nbv != NULL && nbv->bUseGPU;
 }
 
-void init_forcerec(FILE              *fp,
-                   t_forcerec        *fr,
-                   t_fcdata          *fcd,
-                   const t_inputrec  *ir,
-                   const gmx_mtop_t  *mtop,
-                   const t_commrec   *cr,
-                   matrix             box,
-                   const char        *tabfn,
-                   const char        *tabpfn,
-                   const t_filenm    *tabbfnm,
-                   const char        *nbpu_opt,
-                   gmx_bool           bNoSolvOpt,
-                   real               print_force)
+void init_forcerec(FILE                *fp,
+                   const gmx::MDLogger &mdlog,
+                   t_forcerec          *fr,
+                   t_fcdata            *fcd,
+                   const t_inputrec    *ir,
+                   const gmx_mtop_t    *mtop,
+                   const t_commrec     *cr,
+                   matrix               box,
+                   const char          *tabfn,
+                   const char          *tabpfn,
+                   const t_filenm      *tabbfnm,
+                   const char          *nbpu_opt,
+                   gmx_bool             bNoSolvOpt,
+                   real                 print_force)
 {
     int            i, m, negp_pp, negptable, egi, egj;
     real           rtab;
@@ -2343,7 +2331,7 @@ void init_forcerec(FILE              *fp,
          * In mdrun, hwinfo has already been set before calling init_forcerec.
          * Here we ignore GPUs, as tools will not use them anyhow.
          */
-        fr->hwinfo = gmx_detect_hardware(fp, cr, FALSE);
+        fr->hwinfo = gmx_detect_hardware(mdlog, cr, FALSE);
     }
 
     /* By default we turn SIMD kernels on, but it might be turned off further down... */
@@ -2436,9 +2424,9 @@ void init_forcerec(FILE              *fp,
     {
         /* turn off non-bonded calculations */
         fr->bNonbonded = FALSE;
-        md_print_warn(cr, fp,
-                      "Found environment variable GMX_NO_NONBONDED.\n"
-                      "Disabling nonbonded calculations.\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText(
+                "Found environment variable GMX_NO_NONBONDED.\n"
+                "Disabling nonbonded calculations.");
     }
 
     bGenericKernelOnly = FALSE;
@@ -2557,12 +2545,12 @@ void init_forcerec(FILE              *fp,
                     fr->bMolPBC = FALSE;
                     if (fp)
                     {
-                        md_print_warn(cr, fp, "GMX_USE_GRAPH is set, using the graph for bonded interactions\n");
+                        GMX_LOG(mdlog.warning).asParagraph().appendText("GMX_USE_GRAPH is set, using the graph for bonded interactions");
                     }
 
                     if (mtop->bIntermolecularInteractions)
                     {
-                        md_print_warn(cr, fp, "WARNING: Molecules linked by intermolecular interactions have to reside in the same periodic image, otherwise artifacts will occur!\n");
+                        GMX_LOG(mdlog.warning).asParagraph().appendText("WARNING: Molecules linked by intermolecular interactions have to reside in the same periodic image, otherwise artifacts will occur!");
                     }
                 }
 
@@ -2753,6 +2741,9 @@ void init_forcerec(FILE              *fp,
         fr->bcoultab = FALSE;
     }
 
+    /* This now calculates sum for q and C6 */
+    set_chargesum(fp, fr, mtop);
+
     /* Tables are used for direct ewald sum */
     if (fr->bEwald)
     {
@@ -2774,11 +2765,18 @@ void init_forcerec(FILE              *fp,
 
             if (ir->ewald_geometry == eewg3DC)
             {
+                bool haveNetCharge = (fabs(fr->qsum[0]) > 1e-4 ||
+                                      fabs(fr->qsum[1]) > 1e-4);
                 if (fp)
                 {
-                    fprintf(fp, "Using the Ewald3DC correction for systems with a slab geometry.\n");
+                    fprintf(fp, "Using the Ewald3DC correction for systems with a slab geometry%s.\n",
+                            haveNetCharge ? " and net charge" : "");
                 }
                 please_cite(fp, "In-Chul99a");
+                if (haveNetCharge)
+                {
+                    please_cite(fp, "Ballenegger2009");
+                }
             }
         }
         fr->ewaldcoeff_q = calc_ewaldcoeff_q(ir->rcoulomb, ir->ewald_rtol);
@@ -2821,9 +2819,17 @@ void init_forcerec(FILE              *fp,
 
     fr->bF_NoVirSum = (EEL_FULL(fr->eeltype) || EVDW_PME(fr->vdwtype) ||
                        gmx_mtop_ftype_count(mtop, F_POSRES) > 0 ||
-                       gmx_mtop_ftype_count(mtop, F_FBPOSRES) > 0 ||
-                       inputrecElecField(ir)
-                       );
+                       gmx_mtop_ftype_count(mtop, F_FBPOSRES) > 0);
+
+    /* Initialization call after setting bF_NoVirSum,
+     * since it efield->initForcerec also sets this to true.
+     */
+    ir->efield->initForcerec(fr);
+
+    if (fr->bF_NoVirSum)
+    {
+        fr->forceBufferNoVirialSummation = new PaddedRVecVector;
+    }
 
     if (fr->cutoff_scheme == ecutsGROUP &&
         ncg_mtop(mtop) > fr->cg_nalloc && !DOMAINDECOMP(cr))
@@ -2979,9 +2985,6 @@ void init_forcerec(FILE              *fp,
                    &fr->kappa, &fr->k_rf, &fr->c_rf);
     }
 
-    /*This now calculates sum for q and c6*/
-    set_chargesum(fp, fr, mtop);
-
     /* Construct tables for the group scheme. A little unnecessary to
      * make both vdw and coul tables sometimes, but what the
      * heck. Note that both cutoff schemes construct Ewald tables in
@@ -3204,7 +3207,7 @@ void init_forcerec(FILE              *fp,
             GMX_RELEASE_ASSERT(ir->rcoulomb == ir->rvdw, "With Verlet lists and no PME rcoulomb and rvdw should be identical");
         }
 
-        init_nb_verlet(fp, &fr->nbv, bFEP_NonBonded, ir, fr, cr, nbpu_opt);
+        init_nb_verlet(fp, mdlog, &fr->nbv, bFEP_NonBonded, ir, fr, cr, nbpu_opt);
     }
 
     if (ir->eDispCorr != edispcNO)
index 274d909bf82446a41c62461e03acac7e2639f165..f1aba0e1c3e3035ec36b5886e3d6bac3e775c93b 100644 (file)
@@ -48,6 +48,11 @@ struct t_commrec;
 struct t_fcdata;
 struct t_filenm;
 
+namespace gmx
+{
+class MDLogger;
+}
+
 /*! \brief Create a new forcerec structure */
 t_forcerec *mk_forcerec(void);
 
@@ -91,6 +96,7 @@ void init_interaction_const_tables(FILE                   *fp,
  *
  * The Force rec struct must be created with mk_forcerec.
  * \param[in]  fplog       File for printing
+ * \param[in]  mdlog       File for printing
  * \param[out] fr          The forcerec
  * \param[in]  fcd         Force constant data
  * \param[in]  ir          Inputrec structure
@@ -105,6 +111,7 @@ void init_interaction_const_tables(FILE                   *fp,
  * \param[in]  print_force Print forces for atoms with force >= print_force
  */
 void init_forcerec(FILE                   *fplog,
+                   const gmx::MDLogger    &mdlog,
                    t_forcerec             *fr,
                    t_fcdata               *fcd,
                    const t_inputrec       *ir,
index 479ca6592817f2fd06b65680c8148f141563adbd..f4aa5a919cebca88cfc268d40b38d26d341a7b2c 100644 (file)
 #include <cstdlib>
 #include <cstring>
 
-#include "gromacs/gmxlib/md_logging.h"
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/gmxomp.h"
+#include "gromacs/utility/logger.h"
 #include "gromacs/utility/programcontext.h"
 
 /** Structure with the number of threads for each OpenMP multi-threaded
@@ -107,14 +107,12 @@ static omp_module_nthreads_t modth = { 0, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0}, FALSE}
  *  The "group" scheme supports OpenMP only in PME and in thise case all but
  *  the PME nthread values default to 1.
  */
-static void pick_module_nthreads(FILE *fplog, int m,
-                                 gmx_bool bSimMaster,
+static void pick_module_nthreads(const gmx::MDLogger &mdlog, int m,
                                  gmx_bool bFullOmpSupport,
                                  gmx_bool bSepPME)
 {
     char      *env;
     int        nth;
-    char       sbuf[STRLEN];
 
     const bool bOMP = GMX_OPENMP;
 
@@ -130,6 +128,7 @@ static void pick_module_nthreads(FILE *fplog, int m,
     {
         sscanf(env, "%d", &nth);
 
+        // cppcheck-suppress knownConditionTrueFalse
         if (!bOMP)
         {
             gmx_warning("%s=%d is set, but %s is compiled without OpenMP!",
@@ -161,16 +160,9 @@ static void pick_module_nthreads(FILE *fplog, int m,
         /* only babble if we are really overriding with a different value */
         if ((bSepPME && m == emntPME && nth != modth.gnth_pme) || (nth != modth.gnth))
         {
-            sprintf(sbuf, "%s=%d set, overriding the default number of %s threads",
+            GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                    "%s=%d set, overriding the default number of %s threads",
                     modth_env_var[m], nth, mod_name[m]);
-            if (bSimMaster)
-            {
-                fprintf(stderr, "\n%s\n", sbuf);
-            }
-            if (fplog)
-            {
-                fprintf(fplog, "%s\n", sbuf);
-            }
         }
     }
     else
@@ -235,16 +227,16 @@ void gmx_omp_nthreads_read_env(int     *nthreads_omp,
 /*! \brief Helper function for parsing various input about the number
     of OpenMP threads to use in various modules and deciding what to
     do about it. */
-static void manage_number_of_openmp_threads(FILE               *fplog,
-                                            const t_commrec    *cr,
-                                            bool                bOMP,
-                                            int                 nthreads_hw_avail,
-                                            int                 omp_nthreads_req,
-                                            int                 omp_nthreads_pme_req,
-                                            gmx_bool gmx_unused bThisNodePMEOnly,
-                                            gmx_bool            bFullOmpSupport,
-                                            int                 nppn,
-                                            gmx_bool            bSepPME)
+static void manage_number_of_openmp_threads(const gmx::MDLogger &mdlog,
+                                            const t_commrec     *cr,
+                                            bool                 bOMP,
+                                            int                  nthreads_hw_avail,
+                                            int                  omp_nthreads_req,
+                                            int                  omp_nthreads_pme_req,
+                                            gmx_bool gmx_unused  bThisNodePMEOnly,
+                                            gmx_bool             bFullOmpSupport,
+                                            int                  nppn,
+                                            gmx_bool             bSepPME)
 {
     int      nth;
     char    *env;
@@ -258,6 +250,8 @@ static void manage_number_of_openmp_threads(FILE               *fplog,
     {
         return;
     }
+#else
+    GMX_UNUSED_VALUE(cr);
 #endif
 
     if (modth.initialized)
@@ -352,15 +346,15 @@ static void manage_number_of_openmp_threads(FILE               *fplog,
 
     /* now set the per-module values */
     modth.nth[emntDefault] = modth.gnth;
-    pick_module_nthreads(fplog, emntDomdec, SIMMASTER(cr), bFullOmpSupport, bSepPME);
-    pick_module_nthreads(fplog, emntPairsearch, SIMMASTER(cr), bFullOmpSupport, bSepPME);
-    pick_module_nthreads(fplog, emntNonbonded, SIMMASTER(cr), bFullOmpSupport, bSepPME);
-    pick_module_nthreads(fplog, emntBonded, SIMMASTER(cr), bFullOmpSupport, bSepPME);
-    pick_module_nthreads(fplog, emntPME, SIMMASTER(cr), bFullOmpSupport, bSepPME);
-    pick_module_nthreads(fplog, emntUpdate, SIMMASTER(cr), bFullOmpSupport, bSepPME);
-    pick_module_nthreads(fplog, emntVSITE, SIMMASTER(cr), bFullOmpSupport, bSepPME);
-    pick_module_nthreads(fplog, emntLINCS, SIMMASTER(cr), bFullOmpSupport, bSepPME);
-    pick_module_nthreads(fplog, emntSETTLE, SIMMASTER(cr), bFullOmpSupport, bSepPME);
+    pick_module_nthreads(mdlog, emntDomdec, bFullOmpSupport, bSepPME);
+    pick_module_nthreads(mdlog, emntPairsearch, bFullOmpSupport, bSepPME);
+    pick_module_nthreads(mdlog, emntNonbonded, bFullOmpSupport, bSepPME);
+    pick_module_nthreads(mdlog, emntBonded, bFullOmpSupport, bSepPME);
+    pick_module_nthreads(mdlog, emntPME, bFullOmpSupport, bSepPME);
+    pick_module_nthreads(mdlog, emntUpdate, bFullOmpSupport, bSepPME);
+    pick_module_nthreads(mdlog, emntVSITE, bFullOmpSupport, bSepPME);
+    pick_module_nthreads(mdlog, emntLINCS, bFullOmpSupport, bSepPME);
+    pick_module_nthreads(mdlog, emntSETTLE, bFullOmpSupport, bSepPME);
 
     /* set the number of threads globally */
     if (bOMP)
@@ -389,11 +383,11 @@ static void manage_number_of_openmp_threads(FILE               *fplog,
 
 /*! \brief Report on the OpenMP settings that will be used */
 static void
-reportOpenmpSettings(FILE            *fplog,
-                     const t_commrec *cr,
-                     gmx_bool         bOMP,
-                     gmx_bool         bFullOmpSupport,
-                     gmx_bool         bSepPME)
+reportOpenmpSettings(const gmx::MDLogger &mdlog,
+                     const t_commrec     *cr,
+                     gmx_bool             bOMP,
+                     gmx_bool             bFullOmpSupport,
+                     gmx_bool             bSepPME)
 {
 #if GMX_THREAD_MPI
     const char *mpi_str = "per tMPI thread";
@@ -440,31 +434,35 @@ reportOpenmpSettings(FILE            *fplog,
     {
         if (nth_max == nth_min)
         {
-            md_print_info(cr, fplog, "Using %d OpenMP thread%s %s\n",
-                          nth_min, nth_min > 1 ? "s" : "",
-                          cr->nnodes > 1 ? mpi_str : "");
+            GMX_LOG(mdlog.warning).appendTextFormatted(
+                    "Using %d OpenMP thread%s %s",
+                    nth_min, nth_min > 1 ? "s" : "",
+                    cr->nnodes > 1 ? mpi_str : "");
         }
         else
         {
-            md_print_info(cr, fplog, "Using %d - %d OpenMP threads %s\n",
-                          nth_min, nth_max, mpi_str);
+            GMX_LOG(mdlog.warning).appendTextFormatted(
+                    "Using %d - %d OpenMP threads %s",
+                    nth_min, nth_max, mpi_str);
         }
     }
     if (bSepPME && (nth_pme_min != nth_min || nth_pme_max != nth_max))
     {
         if (nth_pme_max == nth_pme_min)
         {
-            md_print_info(cr, fplog, "Using %d OpenMP thread%s %s for PME\n",
-                          nth_pme_min, nth_pme_min > 1 ? "s" : "",
-                          cr->nnodes > 1 ? mpi_str : "");
+            GMX_LOG(mdlog.warning).appendTextFormatted(
+                    "Using %d OpenMP thread%s %s for PME",
+                    nth_pme_min, nth_pme_min > 1 ? "s" : "",
+                    cr->nnodes > 1 ? mpi_str : "");
         }
         else
         {
-            md_print_info(cr, fplog, "Using %d - %d OpenMP threads %s for PME\n",
-                          nth_pme_min, nth_pme_max, mpi_str);
+            GMX_LOG(mdlog.warning).appendTextFormatted(
+                    "Using %d - %d OpenMP threads %s for PME",
+                    nth_pme_min, nth_pme_max, mpi_str);
         }
     }
-    md_print_info(cr, fplog, "\n");
+    GMX_LOG(mdlog.warning);
 }
 
 /*! \brief Detect and warn about oversubscription of cores.
@@ -474,11 +472,11 @@ reportOpenmpSettings(FILE            *fplog,
  *
  * \todo Enable this for separate PME nodes as well! */
 static void
-issueOversubscriptionWarning(FILE            *fplog,
-                             const t_commrec *cr,
-                             int              nthreads_hw_avail,
-                             int              nppn,
-                             gmx_bool         bSepPME)
+issueOversubscriptionWarning(const gmx::MDLogger &mdlog,
+                             const t_commrec     *cr,
+                             int                  nthreads_hw_avail,
+                             int                  nppn,
+                             gmx_bool             bSepPME)
 {
     char sbuf[STRLEN], sbuf1[STRLEN], sbuf2[STRLEN];
 
@@ -504,14 +502,14 @@ issueOversubscriptionWarning(FILE            *fplog,
 #endif
         }
 #endif
-        md_print_warn(cr, fplog,
-                      "WARNING: %sversubscribing the available %d logical CPU cores%s with %d %s.\n"
-                      "         This will cause considerable performance loss!",
-                      sbuf2, nthreads_hw_avail, sbuf1, nppn*modth.gnth, sbuf);
+        GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                "WARNING: %sversubscribing the available %d logical CPU cores%s with %d %s.\n"
+                "         This will cause considerable performance loss!",
+                sbuf2, nthreads_hw_avail, sbuf1, nppn*modth.gnth, sbuf);
     }
 }
 
-void gmx_omp_nthreads_init(FILE *fplog, t_commrec *cr,
+void gmx_omp_nthreads_init(const gmx::MDLogger &mdlog, t_commrec *cr,
                            int nthreads_hw_avail,
                            int omp_nthreads_req,
                            int omp_nthreads_pme_req,
@@ -529,7 +527,7 @@ void gmx_omp_nthreads_init(FILE *fplog, t_commrec *cr,
     bSepPME = ( (cr->duty & DUTY_PP) && !(cr->duty & DUTY_PME)) ||
         (!(cr->duty & DUTY_PP) &&  (cr->duty & DUTY_PME));
 
-    manage_number_of_openmp_threads(fplog, cr, bOMP,
+    manage_number_of_openmp_threads(mdlog, cr, bOMP,
                                     nthreads_hw_avail,
                                     omp_nthreads_req, omp_nthreads_pme_req,
                                     bThisNodePMEOnly, bFullOmpSupport,
@@ -544,8 +542,8 @@ void gmx_omp_nthreads_init(FILE *fplog, t_commrec *cr,
     }
 #endif
 
-    reportOpenmpSettings(fplog, cr, bOMP, bFullOmpSupport, bSepPME);
-    issueOversubscriptionWarning(fplog, cr, nthreads_hw_avail, nppn, bSepPME);
+    reportOpenmpSettings(mdlog, cr, bOMP, bFullOmpSupport, bSepPME);
+    issueOversubscriptionWarning(mdlog, cr, nthreads_hw_avail, nppn, bSepPME);
 }
 
 int gmx_omp_nthreads_get(int mod)
index 92ac2ceb54485b3613485c9c0fbccad5d9f124a7..dfa8f7944e9547aa05c0aae0f088d3ae34c22a48 100644 (file)
 
 struct t_commrec;
 
+namespace gmx
+{
+class MDLogger;
+}
+
 /** Enum values corresponding to multithreaded algorithmic modules. */
 typedef enum module_nth
 {
@@ -58,7 +63,7 @@ typedef enum module_nth
  * It is compatible with tMPI, thread-safety is ensured (for the features
  * available with tMPI).
  * This function should caled only once during the initialization of mdrun. */
-void gmx_omp_nthreads_init(FILE *fplog, t_commrec *cr,
+void gmx_omp_nthreads_init(const gmx::MDLogger &fplog, t_commrec *cr,
                            int nthreads_hw_avail,
                            int omp_nthreads_req,
                            int omp_nthreads_pme_req,
index aea0ec37ab5f7d9ea6f7fc0c970547fd6a113aaa..962e0edd3b417e26a95dcb40f62269a5a14561ce 100644 (file)
@@ -54,6 +54,7 @@
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 
+class energyhistory_t;
 struct gmx_mtop_t;
 struct gmx_membed_t;
 struct gmx_output_env_t;
@@ -63,10 +64,14 @@ struct t_inputrec;
 
 namespace gmx
 {
+
+class MDLogger;
+
 /*! \brief Integrator algorithm implementation.
  *
  * \param[in] fplog               Log file for output
  * \param[in] cr                  Communication record
+ * \param[in] mdlog               Log writer for important output
  * \param[in] nfile               Number of files
  * \param[in] fnm                 Filename structure array
  * \param[in] oenv                Output information
@@ -79,6 +84,7 @@ namespace gmx
  * \param[in] top_global          Molecular topology for the whole system
  * \param[in] fcd                 Force and constraint data
  * \param[in] state_global        The state (x, v, f, box etc.) of the whole system
+ * \param[in] energyHistory       The energy statistics history
  * \param[in] mdatoms             Structure containing atom information
  * \param[in] nrnb                Accounting for floating point operations
  * \param[in] wcycle              Wall cycle timing information
@@ -94,7 +100,7 @@ namespace gmx
  * \param[in] Flags               Flags to control mdrun
  * \param[in] walltime_accounting More timing information
  */
-typedef double integrator_t (FILE *fplog, t_commrec *cr,
+typedef double integrator_t (FILE *fplog, t_commrec *cr, const gmx::MDLogger &mdlog,
                              int nfile, const t_filenm fnm[],
                              const gmx_output_env_t *oenv, gmx_bool bVerbose,
                              int nstglobalcomm,
@@ -103,6 +109,7 @@ typedef double integrator_t (FILE *fplog, t_commrec *cr,
                              t_inputrec *inputrec,
                              gmx_mtop_t *top_global, t_fcdata *fcd,
                              t_state *state_global,
+                             energyhistory_t *energyHistory,
                              t_mdatoms *mdatoms,
                              t_nrnb *nrnb, gmx_wallcycle_t wcycle,
                              gmx_edsam_t ed,
index 4ad4c7732b722e5dd0a4f687aaec1b603a9ca050..5ef335d81b0c374e5de865a5120067afe0117b96 100644 (file)
@@ -44,7 +44,6 @@
 #include <algorithm>
 
 #include "gromacs/domdec/domdec.h"
-#include "gromacs/gmxlib/md_logging.h"
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/gmxlib/nrnb.h"
 #include "gromacs/math/vec.h"
@@ -69,6 +68,7 @@
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/logger.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/snprintf.h"
 
@@ -146,93 +146,6 @@ int multisim_min(const gmx_multisim_t *ms, int nmin, int n)
     return nmin;
 }
 
-void copy_coupling_state(t_state *statea, t_state *stateb,
-                         gmx_ekindata_t *ekinda, gmx_ekindata_t *ekindb, t_grpopts* opts)
-{
-
-    /* MRS note -- might be able to get rid of some of the arguments.  Look over it when it's all debugged */
-
-    int i, j, nc;
-
-    /* Make sure we have enough space for x and v */
-    if (statea->nalloc > stateb->nalloc)
-    {
-        stateb->nalloc = statea->nalloc;
-        /* We need to allocate one element extra, since we might use
-         * (unaligned) 4-wide SIMD loads to access rvec entries.
-         */
-        srenew(stateb->x, stateb->nalloc + 1);
-        srenew(stateb->v, stateb->nalloc + 1);
-    }
-
-    stateb->natoms     = statea->natoms;
-    stateb->ngtc       = statea->ngtc;
-    stateb->nnhpres    = statea->nnhpres;
-    stateb->veta       = statea->veta;
-    if (ekinda)
-    {
-        copy_mat(ekinda->ekin, ekindb->ekin);
-        for (i = 0; i < stateb->ngtc; i++)
-        {
-            ekindb->tcstat[i].T  = ekinda->tcstat[i].T;
-            ekindb->tcstat[i].Th = ekinda->tcstat[i].Th;
-            copy_mat(ekinda->tcstat[i].ekinh, ekindb->tcstat[i].ekinh);
-            copy_mat(ekinda->tcstat[i].ekinf, ekindb->tcstat[i].ekinf);
-            ekindb->tcstat[i].ekinscalef_nhc =  ekinda->tcstat[i].ekinscalef_nhc;
-            ekindb->tcstat[i].ekinscaleh_nhc =  ekinda->tcstat[i].ekinscaleh_nhc;
-            ekindb->tcstat[i].vscale_nhc     =  ekinda->tcstat[i].vscale_nhc;
-        }
-    }
-    copy_rvecn(statea->x, stateb->x, 0, stateb->natoms);
-    copy_rvecn(statea->v, stateb->v, 0, stateb->natoms);
-    copy_mat(statea->box, stateb->box);
-    copy_mat(statea->box_rel, stateb->box_rel);
-    copy_mat(statea->boxv, stateb->boxv);
-
-    for (i = 0; i < stateb->ngtc; i++)
-    {
-        nc = i*opts->nhchainlength;
-        for (j = 0; j < opts->nhchainlength; j++)
-        {
-            stateb->nosehoover_xi[nc+j]  = statea->nosehoover_xi[nc+j];
-            stateb->nosehoover_vxi[nc+j] = statea->nosehoover_vxi[nc+j];
-        }
-    }
-    if (stateb->nhpres_xi != NULL)
-    {
-        for (i = 0; i < stateb->nnhpres; i++)
-        {
-            nc = i*opts->nhchainlength;
-            for (j = 0; j < opts->nhchainlength; j++)
-            {
-                stateb->nhpres_xi[nc+j]  = statea->nhpres_xi[nc+j];
-                stateb->nhpres_vxi[nc+j] = statea->nhpres_vxi[nc+j];
-            }
-        }
-    }
-}
-
-real compute_conserved_from_auxiliary(t_inputrec *ir, t_state *state, t_extmass *MassQ)
-{
-    real quantity = 0;
-    switch (ir->etc)
-    {
-        case etcNO:
-            break;
-        case etcBERENDSEN:
-            break;
-        case etcNOSEHOOVER:
-            quantity = NPT_energy(ir, state, MassQ);
-            break;
-        case etcVRESCALE:
-            quantity = vrescale_energy(&(ir->opts), state->therm_integral);
-            break;
-        default:
-            break;
-    }
-    return quantity;
-}
-
 /* TODO Specialize this routine into init-time and loop-time versions?
    e.g. bReadEkin is only true when restoring from checkpoint */
 void compute_globals(FILE *fplog, gmx_global_stat *gstat, t_commrec *cr, t_inputrec *ir,
@@ -291,7 +204,7 @@ void compute_globals(FILE *fplog, gmx_global_stat *gstat, t_commrec *cr, t_input
     if (bStopCM)
     {
         calc_vcm_grp(0, mdatoms->homenr, mdatoms,
-                     state->x, state->v, vcm);
+                     as_rvec_array(state->x.data()), as_rvec_array(state->v.data()), vcm);
     }
 
     if (bTemp || bStopCM || bPres || bEner || bConstrain)
@@ -326,7 +239,7 @@ void compute_globals(FILE *fplog, gmx_global_stat *gstat, t_commrec *cr, t_input
     {
         correct_ekin(debug,
                      0, mdatoms->homenr,
-                     state->v, vcm->group_p[0],
+                     as_rvec_array(state->v.data()), vcm->group_p[0],
                      mdatoms->massT, mdatoms->tmass, ekind->ekin);
     }
 
@@ -335,7 +248,7 @@ void compute_globals(FILE *fplog, gmx_global_stat *gstat, t_commrec *cr, t_input
     {
         check_cm_grp(fplog, vcm, ir, 1);
         do_stopcm_grp(0, mdatoms->homenr, mdatoms->cVCM,
-                      state->x, state->v, vcm);
+                      as_rvec_array(state->x.data()), as_rvec_array(state->v.data()), vcm);
         inc_nrnb(nrnb, eNR_STOPCM, mdatoms->homenr);
     }
 
@@ -400,16 +313,18 @@ void compute_globals(FILE *fplog, gmx_global_stat *gstat, t_commrec *cr, t_input
     }
 }
 
-void check_nst_param(FILE *fplog, t_commrec *cr,
-                     const char *desc_nst, int nst,
-                     const char *desc_p, int *p)
+/* check whether an 'nst'-style parameter p is a multiple of nst, and
+   set it to be one if not, with a warning. */
+static void check_nst_param(const gmx::MDLogger &mdlog,
+                            const char *desc_nst, int nst,
+                            const char *desc_p, int *p)
 {
     if (*p > 0 && *p % nst != 0)
     {
         /* Round up to the next multiple of nst */
         *p = ((*p)/nst + 1)*nst;
-        md_print_warn(cr, fplog,
-                      "NOTE: %s changes %s to %d\n", desc_nst, desc_p, *p);
+        GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                "NOTE: %s changes %s to %d", desc_nst, desc_p, *p);
     }
 }
 
@@ -537,8 +452,7 @@ static int lcd4(int i1, int i2, int i3, int i4)
     return nst;
 }
 
-int check_nstglobalcomm(FILE *fplog, t_commrec *cr,
-                        int nstglobalcomm, t_inputrec *ir)
+int check_nstglobalcomm(const gmx::MDLogger &mdlog, int nstglobalcomm, t_inputrec *ir)
 {
     if (!EI_DYNAMICS(ir->eI))
     {
@@ -586,42 +500,43 @@ int check_nstglobalcomm(FILE *fplog, t_commrec *cr,
             nstglobalcomm > ir->nstlist && nstglobalcomm % ir->nstlist != 0)
         {
             nstglobalcomm = (nstglobalcomm / ir->nstlist)*ir->nstlist;
-            md_print_warn(cr, fplog, "WARNING: nstglobalcomm is larger than nstlist, but not a multiple, setting it to %d\n", nstglobalcomm);
+            GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                    "WARNING: nstglobalcomm is larger than nstlist, but not a multiple, setting it to %d",
+                    nstglobalcomm);
         }
         if (ir->nstcalcenergy > 0)
         {
-            check_nst_param(fplog, cr, "-gcom", nstglobalcomm,
+            check_nst_param(mdlog, "-gcom", nstglobalcomm,
                             "nstcalcenergy", &ir->nstcalcenergy);
         }
         if (ir->etc != etcNO && ir->nsttcouple > 0)
         {
-            check_nst_param(fplog, cr, "-gcom", nstglobalcomm,
+            check_nst_param(mdlog, "-gcom", nstglobalcomm,
                             "nsttcouple", &ir->nsttcouple);
         }
         if (ir->epc != epcNO && ir->nstpcouple > 0)
         {
-            check_nst_param(fplog, cr, "-gcom", nstglobalcomm,
+            check_nst_param(mdlog, "-gcom", nstglobalcomm,
                             "nstpcouple", &ir->nstpcouple);
         }
 
-        check_nst_param(fplog, cr, "-gcom", nstglobalcomm,
+        check_nst_param(mdlog, "-gcom", nstglobalcomm,
                         "nstenergy", &ir->nstenergy);
 
-        check_nst_param(fplog, cr, "-gcom", nstglobalcomm,
+        check_nst_param(mdlog, "-gcom", nstglobalcomm,
                         "nstlog", &ir->nstlog);
     }
 
     if (ir->comm_mode != ecmNO && ir->nstcomm < nstglobalcomm)
     {
-        md_print_warn(cr, fplog, "WARNING: Changing nstcomm from %d to %d\n",
-                      ir->nstcomm, nstglobalcomm);
+        GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                "WARNING: Changing nstcomm from %d to %d",
+                ir->nstcomm, nstglobalcomm);
         ir->nstcomm = nstglobalcomm;
     }
 
-    if (fplog)
-    {
-        fprintf(fplog, "Intra-simulation communication will occur every %d steps.\n", nstglobalcomm);
-    }
+    GMX_LOG(mdlog.info).appendTextFormatted(
+            "Intra-simulation communication will occur every %d steps.\n", nstglobalcomm);
     return nstglobalcomm;
 }
 
@@ -656,33 +571,18 @@ void set_state_entries(t_state *state, const t_inputrec *ir)
         state->flags |= (1<<estFEPSTATE);
     }
     state->flags |= (1<<estX);
-    if (state->lambda == NULL)
-    {
-        snew(state->lambda, efptNR);
-    }
-    if (state->x == NULL)
-    {
-        /* We need to allocate one element extra, since we might use
-         * (unaligned) 4-wide SIMD loads to access rvec entries.
-         */
-        snew(state->x, state->nalloc + 1);
-    }
+    state->lambda.resize(efptNR);
+    GMX_RELEASE_ASSERT(state->x.size() >= static_cast<unsigned int>(state->natoms), "We should start a run with an initialized state->x");
     if (EI_DYNAMICS(ir->eI))
     {
         state->flags |= (1<<estV);
-        if (state->v == NULL)
-        {
-            snew(state->v, state->nalloc + 1);
-        }
+        state->v.resize(state->natoms + 1);
     }
     if (ir->eI == eiCG)
     {
         state->flags |= (1<<estCGP);
-        if (state->cg_p == NULL)
-        {
-            /* cg_p is not stored in the tpx file, so we need to allocate it */
-            snew(state->cg_p, state->nalloc + 1);
-        }
+        /* cg_p is not stored in the tpx file, so we need to allocate it */
+        state->cg_p.resize(state->natoms + 1);
     }
 
     state->nnhpres = 0;
@@ -696,23 +596,17 @@ void set_state_entries(t_state *state, const t_inputrec *ir)
         if ((ir->epc == epcPARRINELLORAHMAN) || (ir->epc == epcMTTK))
         {
             state->flags |= (1<<estBOXV);
+            state->flags |= (1<<estPRES_PREV);
         }
-        if (ir->epc != epcNO)
+        if (inputrecNptTrotter(ir) || (inputrecNphTrotter(ir)))
         {
-            if (inputrecNptTrotter(ir) || (inputrecNphTrotter(ir)))
-            {
-                state->nnhpres = 1;
-                state->flags  |= (1<<estNHPRES_XI);
-                state->flags  |= (1<<estNHPRES_VXI);
-                state->flags  |= (1<<estSVIR_PREV);
-                state->flags  |= (1<<estFVIR_PREV);
-                state->flags  |= (1<<estVETA);
-                state->flags  |= (1<<estVOL0);
-            }
-            else
-            {
-                state->flags |= (1<<estPRES_PREV);
-            }
+            state->nnhpres = 1;
+            state->flags  |= (1<<estNHPRES_XI);
+            state->flags  |= (1<<estNHPRES_VXI);
+            state->flags  |= (1<<estSVIR_PREV);
+            state->flags  |= (1<<estFVIR_PREV);
+            state->flags  |= (1<<estVETA);
+            state->flags  |= (1<<estVOL0);
         }
     }
 
@@ -729,8 +623,18 @@ void set_state_entries(t_state *state, const t_inputrec *ir)
 
     init_gtc_state(state, state->ngtc, state->nnhpres, ir->opts.nhchainlength); /* allocate the space for nose-hoover chains */
     init_ekinstate(&state->ekinstate, ir);
-    snew(state->enerhist, 1);
-    init_energyhistory(state->enerhist);
-    init_df_history(&state->dfhist, ir->fepvals->n_lambda);
-    state->swapstate.eSwapCoords = ir->eSwapCoords;
+
+    if (ir->bExpanded)
+    {
+        snew(state->dfhist, 1);
+        init_df_history(state->dfhist, ir->fepvals->n_lambda);
+    }
+    if (ir->eSwapCoords != eswapNO)
+    {
+        if (state->swapstate == NULL)
+        {
+            snew(state->swapstate, 1);
+        }
+        state->swapstate->eSwapCoords = ir->eSwapCoords;
+    }
 }
index ce594fc874068fdfc21f2aded79ad6a49aae78b9..a28460b7e75f461860990af2044374a2d08690f6 100644 (file)
@@ -56,9 +56,8 @@ struct t_trxframe;
 
 namespace gmx
 {
-
+class MDLogger;
 class SimulationSignaller;
-
 }
 
 /* Define a number of flags to better control the information
@@ -92,16 +91,9 @@ class SimulationSignaller;
 /*! \brief Return the number of steps that will take place between
  * intra-simulation communications, given the constraints of the
  * inputrec and the value of mdrun -gcom. */
-int check_nstglobalcomm(FILE       *fplog,
-                        t_commrec  *cr,
-                        int         nstglobalcomm,
-                        t_inputrec *ir);
-
-/* check whether an 'nst'-style parameter p is a multiple of nst, and
-   set it to be one if not, with a warning. */
-void check_nst_param(FILE *fplog, t_commrec *cr,
-                     const char *desc_nst, int nst,
-                     const char *desc_p, int *p);
+int check_nstglobalcomm(const gmx::MDLogger &mdlog,
+                        int                  nstglobalcomm,
+                        t_inputrec          *ir);
 
 /*! \brief Return true if the \p value is equal across the set of multi-simulations
  *
@@ -112,10 +104,6 @@ bool multisim_int_all_are_equal(const gmx_multisim_t *ms,
 void rerun_parallel_comm(t_commrec *cr, t_trxframe *fr,
                          gmx_bool *bNotLastFrame);
 
-/* get the conserved energy associated with the ensemble type*/
-real compute_conserved_from_auxiliary(t_inputrec *ir, t_state *state,
-                                      t_extmass *MassQ);
-
 /* set the lambda values at each step of mdrun when they change */
 void set_current_lambdas(gmx_int64_t step, t_lambda *fepvals, gmx_bool bRerunMD,
                          t_trxframe *rerun_fr, t_state *state_global, t_state *state, double lam0[]);
@@ -123,10 +111,6 @@ void set_current_lambdas(gmx_int64_t step, t_lambda *fepvals, gmx_bool bRerunMD,
 int multisim_min(const gmx_multisim_t *ms, int nmin, int n);
 /* Set an appropriate value for n across the whole multi-simulation */
 
-void copy_coupling_state(t_state *statea, t_state *stateb,
-                         gmx_ekindata_t *ekinda, gmx_ekindata_t *ekindb, t_grpopts* opts);
-/* Copy stuff from state A to state B */
-
 void compute_globals(FILE *fplog, gmx_global_stat *gstat, t_commrec *cr, t_inputrec *ir,
                      t_forcerec *fr, gmx_ekindata_t *ekind,
                      t_state *state, t_mdatoms *mdatoms,
index 63ff5e8b495b08bf6ed2715c681312d3aeaa1214..bbcba4bfaee2e1e580f9798c272f6a1a78eaaa6f 100644 (file)
@@ -45,6 +45,7 @@
 #include "gromacs/mdlib/qmmm.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
+#include "gromacs/topology/mtop_lookup.h"
 #include "gromacs/topology/mtop_util.h"
 #include "gromacs/topology/topology.h"
 #include "gromacs/utility/exceptions.h"
@@ -56,7 +57,7 @@ t_mdatoms *init_mdatoms(FILE *fp, const gmx_mtop_t *mtop, gmx_bool bFreeEnergy)
 {
     int                     a;
     double                  tmA, tmB;
-    t_atom                 *atom;
+    const t_atom           *atom;
     t_mdatoms              *md;
     gmx_mtop_atomloop_all_t aloop;
 
@@ -117,8 +118,6 @@ void atoms2md(const gmx_mtop_t *mtop, const t_inputrec *ir,
               t_mdatoms *md)
 {
     gmx_bool              bLJPME;
-    gmx_mtop_atomlookup_t alook;
-    int                   i;
     const t_grpopts      *opts;
     const gmx_groups_t   *groups;
     int                   nthreads gmx_unused;
@@ -129,17 +128,14 @@ void atoms2md(const gmx_mtop_t *mtop, const t_inputrec *ir,
 
     groups = &mtop->groups;
 
-    /* Index==NULL indicates no DD (unless we have a DD node with no
-     * atoms), so also check for homenr. This should be
-     * signaled properly with an extra parameter or nindex==-1.
-     */
-    if (index == NULL && (homenr > 0))
+    /* nindex>=0 indicates DD where we use an index */
+    if (nindex >= 0)
     {
-        md->nr = mtop->natoms;
+        md->nr = nindex;
     }
     else
     {
-        md->nr = nindex;
+        md->nr = mtop->natoms;
     }
 
     if (md->nr > md->nalloc)
@@ -153,6 +149,7 @@ void atoms2md(const gmx_mtop_t *mtop, const t_inputrec *ir,
         }
         srenew(md->massT, md->nalloc);
         srenew(md->invmass, md->nalloc);
+        srenew(md->invMassPerDim, md->nalloc);
         srenew(md->chargeA, md->nalloc);
         srenew(md->typeA, md->nalloc);
         if (md->nPerturbed)
@@ -222,19 +219,18 @@ void atoms2md(const gmx_mtop_t *mtop, const t_inputrec *ir,
         }
     }
 
-    alook = gmx_mtop_atomlookup_init(mtop);
+    int molb = 0;
 
     // cppcheck-suppress unreadVariable
     nthreads = gmx_omp_nthreads_get(emntDefault);
-#pragma omp parallel for num_threads(nthreads) schedule(static)
-    for (i = 0; i < md->nr; i++)
+#pragma omp parallel for num_threads(nthreads) schedule(static) firstprivate(molb)
+    for (int i = 0; i < md->nr; i++)
     {
         try
         {
             int      g, ag;
             real     mA, mB, fac;
             real     c6, c12;
-            t_atom  *atom;
 
             if (index == NULL)
             {
@@ -242,9 +238,9 @@ void atoms2md(const gmx_mtop_t *mtop, const t_inputrec *ir,
             }
             else
             {
-                ag   = index[i];
+                ag = index[i];
             }
-            gmx_mtop_atomnr_to_atom(alook, ag, &atom);
+            const t_atom &atom = mtopGetAtomParameters(mtop, ag, &molb);
 
             if (md->cFREEZE)
             {
@@ -277,14 +273,14 @@ void atoms2md(const gmx_mtop_t *mtop, const t_inputrec *ir,
                 {
                     /* The friction coefficient is mass/tau_t */
                     fac = ir->delta_t/opts->tau_t[md->cTC ? groups->grpnr[egcTC][ag] : 0];
-                    mA  = 0.5*atom->m*fac;
-                    mB  = 0.5*atom->mB*fac;
+                    mA  = 0.5*atom.m*fac;
+                    mB  = 0.5*atom.mB*fac;
                 }
             }
             else
             {
-                mA = atom->m;
-                mB = atom->mB;
+                mA = atom.m;
+                mB = atom.mB;
             }
             if (md->nMassPerturbed)
             {
@@ -292,9 +288,13 @@ void atoms2md(const gmx_mtop_t *mtop, const t_inputrec *ir,
                 md->massB[i]  = mB;
             }
             md->massT[i]    = mA;
+
             if (mA == 0.0)
             {
-                md->invmass[i]    = 0;
+                md->invmass[i]           = 0;
+                md->invMassPerDim[i][XX] = 0;
+                md->invMassPerDim[i][YY] = 0;
+                md->invMassPerDim[i][ZZ] = 0;
             }
             else if (md->cFREEZE)
             {
@@ -314,17 +314,26 @@ void atoms2md(const gmx_mtop_t *mtop, const t_inputrec *ir,
                      */
                     md->invmass[i]  = 1.0/mA;
                 }
+                for (int d = 0; d < DIM; d++)
+                {
+                    md->invMassPerDim[i][d] = (opts->nFreeze[g][d] ? 0 : 1.0/mA);
+                }
             }
             else
             {
-                md->invmass[i]    = 1.0/mA;
+                md->invmass[i]  = 1.0/mA;
+                for (int d = 0; d < DIM; d++)
+                {
+                    md->invMassPerDim[i][d] = 1.0/mA;
+                }
             }
-            md->chargeA[i]      = atom->q;
-            md->typeA[i]        = atom->type;
+
+            md->chargeA[i]      = atom.q;
+            md->typeA[i]        = atom.type;
             if (bLJPME)
             {
-                c6                = mtop->ffparams.iparams[atom->type*(mtop->ffparams.atnr+1)].lj.c6;
-                c12               = mtop->ffparams.iparams[atom->type*(mtop->ffparams.atnr+1)].lj.c12;
+                c6                = mtop->ffparams.iparams[atom.type*(mtop->ffparams.atnr+1)].lj.c6;
+                c12               = mtop->ffparams.iparams[atom.type*(mtop->ffparams.atnr+1)].lj.c12;
                 md->sqrt_c6A[i]   = sqrt(c6);
                 if (c6 == 0.0 || c12 == 0)
                 {
@@ -338,13 +347,13 @@ void atoms2md(const gmx_mtop_t *mtop, const t_inputrec *ir,
             }
             if (md->nPerturbed)
             {
-                md->bPerturbed[i] = PERTURBED(*atom);
-                md->chargeB[i]    = atom->qB;
-                md->typeB[i]      = atom->typeB;
+                md->bPerturbed[i] = PERTURBED(atom);
+                md->chargeB[i]    = atom.qB;
+                md->typeB[i]      = atom.typeB;
                 if (bLJPME)
                 {
-                    c6                = mtop->ffparams.iparams[atom->typeB*(mtop->ffparams.atnr+1)].lj.c6;
-                    c12               = mtop->ffparams.iparams[atom->typeB*(mtop->ffparams.atnr+1)].lj.c12;
+                    c6                = mtop->ffparams.iparams[atom.typeB*(mtop->ffparams.atnr+1)].lj.c6;
+                    c12               = mtop->ffparams.iparams[atom.typeB*(mtop->ffparams.atnr+1)].lj.c12;
                     md->sqrt_c6B[i]   = sqrt(c6);
                     if (c6 == 0.0 || c12 == 0)
                     {
@@ -357,7 +366,7 @@ void atoms2md(const gmx_mtop_t *mtop, const t_inputrec *ir,
                     md->sigma3B[i]    = 1/(md->sigmaB[i]*md->sigmaB[i]*md->sigmaB[i]);
                 }
             }
-            md->ptype[i]    = atom->ptype;
+            md->ptype[i]    = atom.ptype;
             if (md->cTC)
             {
                 md->cTC[i]    = groups->grpnr[egcTC][ag];
@@ -402,37 +411,49 @@ void atoms2md(const gmx_mtop_t *mtop, const t_inputrec *ir,
         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
     }
 
-    gmx_mtop_atomlookup_destroy(alook);
-
     md->homenr = homenr;
+    /* We set mass, invmass, invMassPerDim and tmass for lambda=0.
+     * For free-energy runs, these should be updated using update_mdatoms().
+     */
+    md->tmass  = md->tmassA;
     md->lambda = 0;
 }
 
 void update_mdatoms(t_mdatoms *md, real lambda)
 {
-    int    al, end;
-    real   L1 = 1.0-lambda;
-
-    end = md->nr;
-
-    if (md->nMassPerturbed)
+    if (md->nMassPerturbed && lambda != md->lambda)
     {
-        for (al = 0; (al < end); al++)
+        real L1 = 1 - lambda;
+
+        /* Update masses of perturbed atoms for the change in lambda */
+        // cppcheck-suppress unreadVariable
+        int gmx_unused nthreads = gmx_omp_nthreads_get(emntDefault);
+#pragma omp parallel for num_threads(nthreads) schedule(static)
+        for (int i = 0; i < md->nr; i++)
         {
-            if (md->bPerturbed[al])
+            if (md->bPerturbed[i])
             {
-                md->massT[al] = L1*md->massA[al]+ lambda*md->massB[al];
-                if (md->invmass[al] > 1.1*ALMOST_ZERO)
+                md->massT[i] = L1*md->massA[i] + lambda*md->massB[i];
+                /* Atoms with invmass 0 or ALMOST_ZERO are massless or frozen
+                 * and their invmass does not depend on lambda.
+                 */
+                if (md->invmass[i] > 1.1*ALMOST_ZERO)
                 {
-                    md->invmass[al] = 1.0/md->massT[al];
+                    md->invmass[i] = 1.0/md->massT[i];
+                    for (int d = 0; d < DIM; d++)
+                    {
+                        if (md->invMassPerDim[i][d] > 1.1*ALMOST_ZERO)
+                        {
+                            md->invMassPerDim[i][d] = md->invmass[i];
+                        }
+                    }
                 }
             }
         }
-        md->tmass = L1*md->tmassA + lambda*md->tmassB;
-    }
-    else
-    {
-        md->tmass = md->tmassA;
+
+        /* Update the system mass for the change in lambda */
+        md->tmass  = L1*md->tmassA + lambda*md->tmassB;
     }
+
     md->lambda = lambda;
 }
index 3b811031ed5445efe327e7695ddc43d20a1c5fb4..dd9dc111d7a8b7939bce21e13f38f09ab068cca0 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2010,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -54,9 +54,16 @@ void atoms2md(const gmx_mtop_t *mtop, const t_inputrec *ir,
               t_mdatoms *md);
 /* This routine copies the atoms->atom struct into md.
  * If index!=NULL only the indexed atoms are copied.
+ * For the masses the A-state (lambda=0) mass is used.
+ * Sets md->lambda = 0.
+ * In free-energy runs, update_mdatoms() should be called after atoms2md()
+ * to set the masses corresponding to the value of lambda at each step.
  */
 
 void update_mdatoms(t_mdatoms *md, real lambda);
-/* (Re)set all the mass parameters */
+/* When necessary, sets all the mass parameters to values corresponding
+ * to the free-energy parameter lambda.
+ * Sets md->lambda = lambda.
+ */
 
 #endif
index 040311b646cfbaad81105c077e36e093c14fd715..e654ae5c49c4879d4635ecf6d417788326df8131 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -1495,41 +1495,34 @@ void print_ebin(ener_file_t fp_ene, gmx_bool bEne, gmx_bool bDR, gmx_bool bOR,
 
 void update_energyhistory(energyhistory_t * enerhist, t_mdebin * mdebin)
 {
-    int i;
+    const t_ebin * const ebin = mdebin->ebin;
 
-    enerhist->nsteps     = mdebin->ebin->nsteps;
-    enerhist->nsum       = mdebin->ebin->nsum;
-    enerhist->nsteps_sim = mdebin->ebin->nsteps_sim;
-    enerhist->nsum_sim   = mdebin->ebin->nsum_sim;
-    enerhist->nener      = mdebin->ebin->nener;
+    enerhist->nsteps     = ebin->nsteps;
+    enerhist->nsum       = ebin->nsum;
+    enerhist->nsteps_sim = ebin->nsteps_sim;
+    enerhist->nsum_sim   = ebin->nsum_sim;
 
-    if (mdebin->ebin->nsum > 0)
+    if (ebin->nsum > 0)
     {
-        /* Check if we need to allocate first */
-        if (enerhist->ener_ave == NULL)
-        {
-            snew(enerhist->ener_ave, enerhist->nener);
-            snew(enerhist->ener_sum, enerhist->nener);
-        }
+        /* This will only actually resize the first time */
+        enerhist->ener_ave.resize(ebin->nener);
+        enerhist->ener_sum.resize(ebin->nener);
 
-        for (i = 0; i < enerhist->nener; i++)
+        for (int i = 0; i < ebin->nener; i++)
         {
-            enerhist->ener_ave[i] = mdebin->ebin->e[i].eav;
-            enerhist->ener_sum[i] = mdebin->ebin->e[i].esum;
+            enerhist->ener_ave[i] = ebin->e[i].eav;
+            enerhist->ener_sum[i] = ebin->e[i].esum;
         }
     }
 
-    if (mdebin->ebin->nsum_sim > 0)
+    if (ebin->nsum_sim > 0)
     {
-        /* Check if we need to allocate first */
-        if (enerhist->ener_sum_sim == NULL)
-        {
-            snew(enerhist->ener_sum_sim, enerhist->nener);
-        }
+        /* This will only actually resize the first time */
+        enerhist->ener_sum_sim.resize(ebin->nener);
 
-        for (i = 0; i < enerhist->nener; i++)
+        for (int i = 0; i < ebin->nener; i++)
         {
-            enerhist->ener_sum_sim[i] = mdebin->ebin->e_sim[i].esum;
+            enerhist->ener_sum_sim[i] = ebin->e_sim[i].esum;
         }
     }
     if (mdebin->dhc)
@@ -1541,13 +1534,13 @@ void update_energyhistory(energyhistory_t * enerhist, t_mdebin * mdebin)
 void restore_energyhistory_from_state(t_mdebin        * mdebin,
                                       energyhistory_t * enerhist)
 {
-    int i;
+    unsigned int nener = static_cast<unsigned int>(mdebin->ebin->nener);
 
-    if ((enerhist->nsum > 0 || enerhist->nsum_sim > 0) &&
-        mdebin->ebin->nener != enerhist->nener)
+    if ((enerhist->nsum     > 0 && nener != enerhist->ener_sum.size()) ||
+        (enerhist->nsum_sim > 0 && nener != enerhist->ener_sum_sim.size()))
     {
-        gmx_fatal(FARGS, "Mismatch between number of energies in run input (%d) and checkpoint file (%d).",
-                  mdebin->ebin->nener, enerhist->nener);
+        gmx_fatal(FARGS, "Mismatch between number of energies in run input (%d) and checkpoint file (%u or %u).",
+                  nener, enerhist->ener_sum.size(), enerhist->ener_sum_sim.size());
     }
 
     mdebin->ebin->nsteps     = enerhist->nsteps;
@@ -1555,7 +1548,7 @@ void restore_energyhistory_from_state(t_mdebin        * mdebin,
     mdebin->ebin->nsteps_sim = enerhist->nsteps_sim;
     mdebin->ebin->nsum_sim   = enerhist->nsum_sim;
 
-    for (i = 0; i < mdebin->ebin->nener; i++)
+    for (int i = 0; i < mdebin->ebin->nener; i++)
     {
         mdebin->ebin->e[i].eav  =
             (enerhist->nsum > 0 ? enerhist->ener_ave[i] : 0);
@@ -1566,6 +1559,6 @@ void restore_energyhistory_from_state(t_mdebin        * mdebin,
     }
     if (mdebin->dhc)
     {
-        mde_delta_h_coll_restore_energyhistory(mdebin->dhc, enerhist);
+        mde_delta_h_coll_restore_energyhistory(mdebin->dhc, enerhist->deltaHForeignLambdas.get());
     }
 }
index d5980f9feef56e0947fbabed2a8e69ee71306a04..a5aff5be00bd1cf67d2d1245b3265ffad6489635 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -44,6 +44,7 @@
 #include "gromacs/mdtypes/forcerec.h"
 #include "gromacs/mdtypes/state.h"
 
+class energyhistory_t;
 struct gmx_constr;
 struct gmx_ekindata_t;
 struct gmx_mtop_t;
@@ -159,13 +160,13 @@ void print_ebin(ener_file_t fp_ene, gmx_bool bEne, gmx_bool bDR, gmx_bool bOR,
 
 /* Between .edr writes, the averages are history dependent,
    and that history needs to be retained in checkpoints.
-   These functions set/read the energyhistory_t structure
+   These functions set/read the energyhistory_t class
    that is written to checkpoints in checkpoint.c */
 
-/* Set the energyhistory_t data structure from a mdebin structure */
+/* Set the energyhistory_t data from a mdebin structure */
 void update_energyhistory(energyhistory_t * enerhist, t_mdebin * mdebin);
 
-/* Read the energyhistory_t data structure to a mdebin structure*/
+/* Read the energyhistory_t data to a mdebin structure*/
 void restore_energyhistory_from_state(t_mdebin        * mdebin,
                                       energyhistory_t * enerhist);
 
index a7d886b73b29200f338adbb9530c4946b88d0d2d..00835be260df2d94c32d9e2775fe176a5040bedc 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 #include <math.h>
 #include <string.h>
 
+#include <cassert>
+
 #include "gromacs/fileio/enxio.h"
 #include "gromacs/mdlib/mdebin.h"
 #include "gromacs/mdtypes/energyhistory.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/smalloc.h"
 
 /* reset the delta_h list to prepare it for new values */
@@ -67,12 +70,12 @@ static void mde_delta_h_init(t_mde_delta_h *dh, int nbins,
 
     dh->type       = type;
     dh->derivative = derivative;
-    dh->lambda     = lambda;
     dh->nlambda    = nlambda;
 
     snew(dh->lambda, nlambda);
     for (i = 0; i < nlambda; i++)
     {
+        assert(lambda);
         dh->lambda[i] = lambda[i];
     }
 
@@ -678,67 +681,51 @@ void mde_delta_h_coll_reset(t_mde_delta_h_coll *dhc)
 }
 
 /* set the energyhistory variables to save state */
-void mde_delta_h_coll_update_energyhistory(t_mde_delta_h_coll *dhc,
-                                           energyhistory_t    *enerhist)
+void mde_delta_h_coll_update_energyhistory(const t_mde_delta_h_coll *dhc,
+                                           energyhistory_t          *enerhist)
 {
-    int i;
-    if (!enerhist->dht)
+    if (enerhist->deltaHForeignLambdas == nullptr)
     {
-        snew(enerhist->dht, 1);
-        snew(enerhist->dht->ndh, dhc->ndh);
-        snew(enerhist->dht->dh, dhc->ndh);
-        enerhist->dht->nndh = dhc->ndh;
+        enerhist->deltaHForeignLambdas.reset(new delta_h_history_t);
+        enerhist->deltaHForeignLambdas->dh.resize(dhc->ndh);
     }
-    else
-    {
-        if (enerhist->dht->nndh != dhc->ndh)
-        {
-            gmx_incons("energy history number of delta_h histograms != inputrec's number");
-        }
-    }
-    for (i = 0; i < dhc->ndh; i++)
+
+    delta_h_history_t * const deltaH = enerhist->deltaHForeignLambdas.get();
+
+    GMX_RELEASE_ASSERT(deltaH->dh.size() == static_cast<size_t>(dhc->ndh), "energy history number of delta_h histograms should match inputrec's number");
+
+    for (int i = 0; i < dhc->ndh; i++)
     {
-        enerhist->dht->dh[i]  = dhc->dh[i].dh;
-        enerhist->dht->ndh[i] = dhc->dh[i].ndh;
+        std::vector<real> &dh = deltaH->dh[i];
+        dh.resize(dhc->dh[i].ndh);
+        std::copy(dh.begin(), dh.end(), dhc->dh[i].dh);
     }
-    enerhist->dht->start_time   = dhc->start_time;
-    enerhist->dht->start_lambda = dhc->start_lambda;
+    deltaH->start_time   = dhc->start_time;
+    deltaH->start_lambda = dhc->start_lambda;
 }
 
 
 
 /* restore the variables from an energyhistory */
-void mde_delta_h_coll_restore_energyhistory(t_mde_delta_h_coll *dhc,
-                                            energyhistory_t    *enerhist)
+void mde_delta_h_coll_restore_energyhistory(t_mde_delta_h_coll      *dhc,
+                                            const delta_h_history_t *deltaH)
 {
-    int          i;
-    unsigned int j;
-
-    if (!dhc)
-    {
-        gmx_incons("No delta_h histograms found");
-    }
-    if (!enerhist->dht)
-    {
-        gmx_incons("No delta_h histograms found in energy history");
-    }
-    if (enerhist->dht->nndh != dhc->ndh)
-    {
-        gmx_incons("energy history number of delta_h histograms != inputrec's number");
-    }
+    GMX_RELEASE_ASSERT(dhc, "Should have delta_h histograms");
+    GMX_RELEASE_ASSERT(deltaH, "Should have delta_h histograms in energy history");
+    GMX_RELEASE_ASSERT(deltaH->dh.size() == static_cast<size_t>(dhc->ndh), "energy history number of delta_h histograms should match inputrec's number");
 
-    for (i = 0; i < enerhist->dht->nndh; i++)
+    for (unsigned int i = 0; i < deltaH->dh.size(); i++)
     {
-        dhc->dh[i].ndh = enerhist->dht->ndh[i];
-        for (j = 0; j < dhc->dh[i].ndh; j++)
+        dhc->dh[i].ndh = deltaH->dh[i].size();
+        for (unsigned int j = 0; j < dhc->dh[i].ndh; j++)
         {
-            dhc->dh[i].dh[j] = enerhist->dht->dh[i][j];
+            dhc->dh[i].dh[j] = deltaH->dh[i][j];
         }
     }
-    dhc->start_time = enerhist->dht->start_time;
-    if (enerhist->dht->start_lambda_set)
+    dhc->start_time = deltaH->start_time;
+    if (deltaH->start_lambda_set)
     {
-        dhc->start_lambda = enerhist->dht->start_lambda;
+        dhc->start_lambda = deltaH->start_lambda;
     }
     if (dhc->dh[0].ndh > 0)
     {
index b0af7caec5dd0b0631ff5ceb5d4f0bb507f24a05..38ca27d6659980b3848941984d323a0fddc693c5 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 
 #include "gromacs/mdlib/mdebin.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
 /* The functions & data structures here describe writing
    energy differences (or their histogram )for use with g_bar */
 
+class delta_h_history_t;
+
 /* Data for one foreign lambda, or derivative. */
 typedef struct
 {
@@ -170,16 +167,11 @@ void mde_delta_h_coll_reset(t_mde_delta_h_coll *dhc);
 
 
 /* set the energyhistory variables to save state */
-void mde_delta_h_coll_update_energyhistory(t_mde_delta_h_coll *dhc,
-                                           energyhistory_t    *enerhist);
+void mde_delta_h_coll_update_energyhistory(const t_mde_delta_h_coll *dhc,
+                                           energyhistory_t          *enerhist);
 
 /* restore the variables from an energyhistory */
-void mde_delta_h_coll_restore_energyhistory(t_mde_delta_h_coll *dhc,
-                                            energyhistory_t    *enerhist);
-
-
-#ifdef __cplusplus
-}
-#endif
+void mde_delta_h_coll_restore_energyhistory(t_mde_delta_h_coll      *dhc,
+                                            const delta_h_history_t *enerhist);
 
 #endif  /* _mdebin_bar_h */
index 1335ad8fe2737c2184bd80247c234f564a5622f0..80f2d5d407e80220e9fb927aa078defbdec5ca59 100644 (file)
@@ -70,7 +70,6 @@ struct gmx_mdoutf {
     int               elamstats;
     int               simulation_part;
     FILE             *fp_dhdl;
-    FILE             *fp_field;
     int               natoms_global;
     int               natoms_x_compressed;
     gmx_groups_t     *groups; /* for compressed position writing */
@@ -97,7 +96,6 @@ gmx_mdoutf_t init_mdoutf(FILE *fplog, int nfile, const t_filenm fnm[],
     of->tng          = NULL;
     of->tng_low_prec = NULL;
     of->fp_dhdl      = NULL;
-    of->fp_field     = NULL;
 
     of->eIntegrator             = ir->eI;
     of->bExpanded               = ir->bExpanded;
@@ -194,21 +192,7 @@ gmx_mdoutf_t init_mdoutf(FILE *fplog, int nfile, const t_filenm fnm[],
             }
         }
 
-        if (opt2bSet("-field", nfile, fnm) &&
-            (ir->ex[XX].n || ir->ex[YY].n || ir->ex[ZZ].n))
-        {
-            if (bAppendFiles)
-            {
-                of->fp_field = gmx_fio_fopen(opt2fn("-field", nfile, fnm),
-                                             filemode);
-            }
-            else
-            {
-                of->fp_field = xvgropen(opt2fn("-field", nfile, fnm),
-                                        "Applied electric field", "Time (ps)",
-                                        "E (V/nm)", oenv);
-            }
-        }
+        ir->efield->initOutput(fplog, nfile, fnm, bAppendFiles, oenv);
 
         /* Set up atom counts so they can be passed to actual
            trajectory-writing routines later. Also, XTC writing needs
@@ -239,11 +223,6 @@ gmx_mdoutf_t init_mdoutf(FILE *fplog, int nfile, const t_filenm fnm[],
     return of;
 }
 
-FILE *mdoutf_get_fp_field(gmx_mdoutf_t of)
-{
-    return of->fp_field;
-}
-
 ener_file_t mdoutf_get_fp_ene(gmx_mdoutf_t of)
 {
     return of->fp_ene;
@@ -265,18 +244,11 @@ void mdoutf_write_to_trajectory_files(FILE *fplog, t_commrec *cr,
                                       gmx_mtop_t *top_global,
                                       gmx_int64_t step, double t,
                                       t_state *state_local, t_state *state_global,
-                                      rvec *f_local)
+                                      energyhistory_t *energyHistory,
+                                      PaddedRVecVector *f_local)
 {
-    rvec *local_v;
-    rvec *global_v;
     rvec *f_global;
 
-    /* MRS -- defining these variables is to manage the difference
-     * between half step and full step velocities, but there must be a better way . . . */
-
-    local_v  = state_local->v;
-    global_v = state_global->v;
-
     if (DOMAINDECOMP(cr))
     {
         if (mdof_flags & MDOF_CPT)
@@ -287,13 +259,13 @@ void mdoutf_write_to_trajectory_files(FILE *fplog, t_commrec *cr,
         {
             if (mdof_flags & (MDOF_X | MDOF_X_COMPRESSED))
             {
-                dd_collect_vec(cr->dd, state_local, state_local->x,
-                               state_global->x);
+                dd_collect_vec(cr->dd, state_local, &state_local->x,
+                               &state_global->x);
             }
             if (mdof_flags & MDOF_V)
             {
-                dd_collect_vec(cr->dd, state_local, local_v,
-                               global_v);
+                dd_collect_vec(cr->dd, state_local, &state_local->v,
+                               &state_global->v);
             }
         }
         f_global = of->f_global;
@@ -304,21 +276,10 @@ void mdoutf_write_to_trajectory_files(FILE *fplog, t_commrec *cr,
     }
     else
     {
-        if (mdof_flags & MDOF_CPT)
-        {
-            /* All pointers in state_local are equal to state_global,
-             * but we need to copy the non-pointer entries.
-             */
-            state_global->lambda = state_local->lambda;
-            state_global->veta   = state_local->veta;
-            state_global->vol0   = state_local->vol0;
-            copy_mat(state_local->box, state_global->box);
-            copy_mat(state_local->boxv, state_global->boxv);
-            copy_mat(state_local->svir_prev, state_global->svir_prev);
-            copy_mat(state_local->fvir_prev, state_global->fvir_prev);
-            copy_mat(state_local->pres_prev, state_global->pres_prev);
-        }
-        f_global = f_local;
+        /* We have the whole state locally: copy the local state pointer */
+        state_global = state_local;
+
+        f_global     = as_rvec_array(f_local->data());
     }
 
     if (MASTER(cr))
@@ -333,18 +294,21 @@ void mdoutf_write_to_trajectory_files(FILE *fplog, t_commrec *cr,
                              DOMAINDECOMP(cr) ? cr->dd->nc : one_ivec,
                              DOMAINDECOMP(cr) ? cr->dd->nnodes : cr->nnodes,
                              of->eIntegrator, of->simulation_part,
-                             of->bExpanded, of->elamstats, step, t, state_global);
+                             of->bExpanded, of->elamstats, step, t,
+                             state_global, energyHistory);
         }
 
         if (mdof_flags & (MDOF_X | MDOF_V | MDOF_F))
         {
+            const rvec *x = (mdof_flags & MDOF_X) ? as_rvec_array(state_global->x.data()) : NULL;
+            const rvec *v = (mdof_flags & MDOF_V) ? as_rvec_array(state_global->v.data()) : NULL;
+            const rvec *f = (mdof_flags & MDOF_F) ? f_global : NULL;
+
             if (of->fp_trn)
             {
                 gmx_trr_write_frame(of->fp_trn, step, t, state_local->lambda[efptFEP],
                                     state_local->box, top_global->natoms,
-                                    (mdof_flags & MDOF_X) ? state_global->x : NULL,
-                                    (mdof_flags & MDOF_V) ? global_v : NULL,
-                                    (mdof_flags & MDOF_F) ? f_global : NULL);
+                                    x, v, f);
                 if (gmx_fio_flush(of->fp_trn) != 0)
                 {
                     gmx_file("Cannot write trajectory; maybe you are out of disk space?");
@@ -358,9 +322,7 @@ void mdoutf_write_to_trajectory_files(FILE *fplog, t_commrec *cr,
                 gmx_fwrite_tng(of->tng, FALSE, step, t, state_local->lambda[efptFEP],
                                state_local->box,
                                top_global->natoms,
-                               (mdof_flags & MDOF_X) ? state_global->x : NULL,
-                               (mdof_flags & MDOF_V) ? global_v : NULL,
-                               (mdof_flags & MDOF_F) ? f_global : NULL);
+                               x, v, f);
             }
             /* If only a TNG file is open for compressed coordinate output (no uncompressed
                coordinate output) also write forces and velocities to it. */
@@ -369,9 +331,7 @@ void mdoutf_write_to_trajectory_files(FILE *fplog, t_commrec *cr,
                 gmx_fwrite_tng(of->tng_low_prec, FALSE, step, t, state_local->lambda[efptFEP],
                                state_local->box,
                                top_global->natoms,
-                               (mdof_flags & MDOF_X) ? state_global->x : NULL,
-                               (mdof_flags & MDOF_V) ? global_v : NULL,
-                               (mdof_flags & MDOF_F) ? f_global : NULL);
+                               x, v, f);
             }
         }
         if (mdof_flags & MDOF_X_COMPRESSED)
@@ -382,7 +342,7 @@ void mdoutf_write_to_trajectory_files(FILE *fplog, t_commrec *cr,
             {
                 /* We are writing the positions of all of the atoms to
                    the compressed output */
-                xxtc = state_global->x;
+                xxtc = as_rvec_array(state_global->x.data());
             }
             else
             {
@@ -434,7 +394,7 @@ void mdoutf_tng_close(gmx_mdoutf_t of)
     }
 }
 
-void done_mdoutf(gmx_mdoutf_t of)
+void done_mdoutf(gmx_mdoutf_t of, const t_inputrec *ir)
 {
     if (of->fp_ene != NULL)
     {
@@ -452,13 +412,7 @@ void done_mdoutf(gmx_mdoutf_t of)
     {
         gmx_fio_fclose(of->fp_dhdl);
     }
-    if (of->fp_field != NULL)
-    {
-        /* This is opened sometimes with xvgropen, sometimes with
-         * gmx_fio_fopen, so we use the least common denominator for closing.
-         */
-        gmx_fio_fclose(of->fp_field);
-    }
+    ir->efield->finishOutput();
     if (of->f_global != NULL)
     {
         sfree(of->f_global);
index f2db7264bfd455d6dd2d0a9d3ee6265b67ba88d5..addd7f042566c781fb8565ad2b5473feeb410d2c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -42,6 +42,7 @@
 #include "gromacs/timing/wallcycle.h"
 #include "gromacs/utility/basedefinitions.h"
 
+class energyhistory_t;
 struct gmx_mtop_t;
 struct gmx_output_env_t;
 struct t_commrec;
@@ -65,9 +66,6 @@ gmx_mdoutf_t init_mdoutf(FILE                   *fplog,
                          const gmx_output_env_t *oenv,
                          gmx_wallcycle_t         wcycle);
 
-/*! \brief Getter for file pointer */
-FILE *mdoutf_get_fp_field(gmx_mdoutf_t of);
-
 /*! \brief Getter for file pointer */
 ener_file_t mdoutf_get_fp_ene(gmx_mdoutf_t of);
 
@@ -85,13 +83,14 @@ gmx_wallcycle_t mdoutf_get_wcycle(gmx_mdoutf_t of);
 void mdoutf_tng_close(gmx_mdoutf_t of);
 
 /*! \brief Close all open output files and free the of pointer */
-void done_mdoutf(gmx_mdoutf_t of);
+void done_mdoutf(gmx_mdoutf_t of, const t_inputrec *ir);
 
 /*! \brief Routine that writes trajectory-like frames.
  *
  * Writes data to trn, xtc and/or checkpoint. What is written is
  * determined by the mdof_flags defined below. Data is collected to
- * the master node only when necessary.
+ * the master node only when necessary. Without domain decomposition
+ * only data from state_local is used and state_global is ignored.
  */
 void mdoutf_write_to_trajectory_files(FILE *fplog, t_commrec *cr,
                                       gmx_mdoutf_t of,
@@ -99,7 +98,8 @@ void mdoutf_write_to_trajectory_files(FILE *fplog, t_commrec *cr,
                                       gmx_mtop_t *top_global,
                                       gmx_int64_t step, double t,
                                       t_state *state_local, t_state *state_global,
-                                      rvec *f_local);
+                                      energyhistory_t *energyHistory,
+                                      PaddedRVecVector *f_local);
 
 #define MDOF_X            (1<<0)
 #define MDOF_V            (1<<1)
diff --git a/src/gromacs/mdlib/mdsetup.cpp b/src/gromacs/mdlib/mdsetup.cpp
new file mode 100644 (file)
index 0000000..3636544
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+#include "gmxpre.h"
+
+#include "mdsetup.h"
+
+#include "gromacs/domdec/domdec.h"
+#include "gromacs/domdec/domdec_struct.h"
+#include "gromacs/listed-forces/manage-threading.h"
+#include "gromacs/mdlib/mdatoms.h"
+#include "gromacs/mdlib/shellfc.h"
+#include "gromacs/mdlib/vsite.h"
+#include "gromacs/mdtypes/commrec.h"
+#include "gromacs/mdtypes/forcerec.h"
+#include "gromacs/mdtypes/inputrec.h"
+#include "gromacs/pbcutil/mshift.h"
+#include "gromacs/pbcutil/pbc.h"
+#include "gromacs/topology/mtop_util.h"
+#include "gromacs/topology/topology.h"
+#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/smalloc.h"
+
+/* TODO: Add a routine that collects the initial setup of the algorithms.
+ *
+ * The final solution should be an MD algorithm base class with methods
+ * for initialization and atom-data setup.
+ */
+
+void mdAlgorithmsSetupAtomData(t_commrec         *cr,
+                               const t_inputrec  *ir,
+                               const gmx_mtop_t  *top_global,
+                               gmx_localtop_t    *top,
+                               t_forcerec        *fr,
+                               t_graph          **graph,
+                               t_mdatoms         *mdatoms,
+                               gmx_vsite_t       *vsite,
+                               gmx_shellfc_t     *shellfc)
+{
+    bool  usingDomDec = DOMAINDECOMP(cr);
+
+    int   numAtomIndex, numHomeAtoms;
+    int  *atomIndex;
+
+    if (usingDomDec)
+    {
+        numAtomIndex = dd_natoms_mdatoms(cr->dd);
+        atomIndex    = cr->dd->gatindex;
+        numHomeAtoms = cr->dd->nat_home;
+    }
+    else
+    {
+        numAtomIndex = -1;
+        atomIndex    = NULL;
+        numHomeAtoms = top_global->natoms;
+    }
+    atoms2md(top_global, ir, numAtomIndex, atomIndex, numHomeAtoms, mdatoms);
+
+    if (usingDomDec)
+    {
+        dd_sort_local_top(cr->dd, mdatoms, top);
+    }
+    else
+    {
+        /* Currently gmx_generate_local_top allocates and returns a pointer.
+         * We should implement a more elegant solution.
+         */
+        gmx_localtop_t *tmpTop;
+
+        tmpTop = gmx_mtop_generate_local_top(top_global, ir->efep != efepNO);
+        *top   = *tmpTop;
+        sfree(tmpTop);
+    }
+
+    if (vsite)
+    {
+        if (usingDomDec)
+        {
+            /* The vsites were already assigned by the domdec topology code.
+             * We only need to do the thread division here.
+             */
+            split_vsites_over_threads(top->idef.il, top->idef.iparams,
+                                      mdatoms, FALSE, vsite);
+        }
+        else
+        {
+            set_vsite_top(vsite, top, mdatoms, cr);
+        }
+    }
+
+    if (!usingDomDec && ir->ePBC != epbcNONE && !fr->bMolPBC)
+    {
+        GMX_ASSERT(graph != NULL, "We use a graph with PBC (no periodic mols) and without DD");
+
+        *graph = mk_graph(NULL, &(top->idef), 0, top_global->natoms, FALSE, FALSE);
+    }
+    else if (graph != NULL)
+    {
+        *graph = NULL;
+    }
+
+    /* Note that with DD only flexible constraints, not shells, are supported
+     * and these don't require setup in make_local_shells().
+     */
+    if (!usingDomDec && shellfc)
+    {
+        make_local_shells(cr, mdatoms, shellfc);
+    }
+
+    setup_bonded_threading(fr, &top->idef);
+}
diff --git a/src/gromacs/mdlib/mdsetup.h b/src/gromacs/mdlib/mdsetup.h
new file mode 100644 (file)
index 0000000..c261643
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+#ifndef GMX_MDLIB_MDSETUP_H
+#define GMX_MDLIB_MDSETUP_H
+
+#include "gromacs/mdlib/mdatoms.h"
+#include "gromacs/mdlib/shellfc.h"
+#include "gromacs/mdlib/vsite.h"
+#include "gromacs/mdtypes/commrec.h"
+#include "gromacs/mdtypes/forcerec.h"
+#include "gromacs/mdtypes/inputrec.h"
+#include "gromacs/pbcutil/mshift.h"
+#include "gromacs/topology/topology.h"
+
+/*! \brief Sets atom data for several MD algorithms
+ *
+ * Most MD algorithms require two different setup calls:
+ * one for initialization and parameter setting and one for atom data setup.
+ * This routine sets the atom data for the (locally available) atoms.
+ * This is called at the start of serial runs and during domain decomposition.
+ *
+ * \param[in]     cr         Communication record
+ * \param[in]     ir         Input parameter record
+ * \param[in]     top_global The global topology
+ * \param[in,out] top        The local topology
+ * \param[in,out] fr         The force calculation parameter/data record
+ * \param[out]    graph      The molecular graph, can be NULL
+ * \param[out]    mdatoms    The MD atom data
+ * \param[in,out] vsite      The virtual site data, can be NULL
+ * \param[in,out] shellfc    The shell/flexible-constraint data, can be NULL
+ */
+void mdAlgorithmsSetupAtomData(t_commrec         *cr,
+                               const t_inputrec  *ir,
+                               const gmx_mtop_t  *top_global,
+                               gmx_localtop_t    *top,
+                               t_forcerec        *fr,
+                               t_graph          **graph,
+                               t_mdatoms         *mdatoms,
+                               gmx_vsite_t       *vsite,
+                               gmx_shellfc_t     *shellfc);
+
+#endif
index 2d5290d4b9502a9d1f900089717a5b1578c490ed..2dcdc2e22853ae57a1b7d1cbf4ed3643ca6b88df 100644 (file)
@@ -61,7 +61,6 @@
 #include "gromacs/ewald/pme.h"
 #include "gromacs/fileio/confio.h"
 #include "gromacs/fileio/mtxio.h"
-#include "gromacs/gmxlib/md_logging.h"
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/gmxlib/nrnb.h"
 #include "gromacs/imd/imd.h"
@@ -77,6 +76,7 @@
 #include "gromacs/mdlib/mdatoms.h"
 #include "gromacs/mdlib/mdebin.h"
 #include "gromacs/mdlib/mdrun.h"
+#include "gromacs/mdlib/mdsetup.h"
 #include "gromacs/mdlib/ns.h"
 #include "gromacs/mdlib/shellfc.h"
 #include "gromacs/mdlib/sim_util.h"
 #include "gromacs/timing/wallcycle.h"
 #include "gromacs/timing/walltime_accounting.h"
 #include "gromacs/topology/mtop_util.h"
+#include "gromacs/topology/topology.h"
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/logger.h"
 #include "gromacs/utility/smalloc.h"
 
 //! Utility structure for manipulating states during EM
 typedef struct {
     //! Copy of the global state
-    t_state  s;
+    t_state          s;
     //! Force array
-    rvec    *f;
+    PaddedRVecVector f;
     //! Potential energy
-    real     epot;
+    real             epot;
     //! Norm of the force
-    real     fnorm;
+    real             fnorm;
     //! Maximum force
-    real     fmax;
+    real             fmax;
     //! Direction
-    int      a_fmax;
+    int              a_fmax;
 } em_state_t;
 
-//! Initiate em_state_t structure and return pointer to it
-static em_state_t *init_em_state()
-{
-    em_state_t *ems;
-
-    snew(ems, 1);
-
-    /* does this need to be here?  Should the array be declared differently (staticaly)in the state definition? */
-    snew(ems->s.lambda, efptNR);
-
-    return ems;
-}
-
 //! Print the EM starting conditions
 static void print_em_start(FILE                     *fplog,
                            t_commrec                *cr,
@@ -195,7 +184,7 @@ static void warn_step(FILE *fp, real ftol, gmx_bool bLastStep, gmx_bool bConstra
 //! Print message about convergence of the EM
 static void print_converged(FILE *fp, const char *alg, real ftol,
                             gmx_int64_t count, gmx_bool bDone, gmx_int64_t nsteps,
-                            real epot, real fmax, int nfmax, real fnorm)
+                            const em_state_t *ems, double sqrtNumAtoms)
 {
     char buf[STEPSTRSIZE];
 
@@ -217,19 +206,19 @@ static void print_converged(FILE *fp, const char *alg, real ftol,
     }
 
 #if GMX_DOUBLE
-    fprintf(fp, "Potential Energy  = %21.14e\n", epot);
-    fprintf(fp, "Maximum force     = %21.14e on atom %d\n", fmax, nfmax+1);
-    fprintf(fp, "Norm of force     = %21.14e\n", fnorm);
+    fprintf(fp, "Potential Energy  = %21.14e\n", ems->epot);
+    fprintf(fp, "Maximum force     = %21.14e on atom %d\n", ems->fmax, ems->a_fmax + 1);
+    fprintf(fp, "Norm of force     = %21.14e\n", ems->fnorm/sqrtNumAtoms);
 #else
-    fprintf(fp, "Potential Energy  = %14.7e\n", epot);
-    fprintf(fp, "Maximum force     = %14.7e on atom %d\n", fmax, nfmax+1);
-    fprintf(fp, "Norm of force     = %14.7e\n", fnorm);
+    fprintf(fp, "Potential Energy  = %14.7e\n", ems->epot);
+    fprintf(fp, "Maximum force     = %14.7e on atom %d\n", ems->fmax, ems->a_fmax + 1);
+    fprintf(fp, "Norm of force     = %14.7e\n", ems->fnorm/sqrtNumAtoms);
 #endif
 }
 
 //! Compute the norm and max of the force array in parallel
 static void get_f_norm_max(t_commrec *cr,
-                           t_grpopts *opts, t_mdatoms *mdatoms, rvec *f,
+                           t_grpopts *opts, t_mdatoms *mdatoms, const rvec *f,
                            real *fnorm, real *fmax, int *a_fmax)
 {
     double fnorm2, *sum;
@@ -326,7 +315,8 @@ static void get_state_f_norm_max(t_commrec *cr,
                                  t_grpopts *opts, t_mdatoms *mdatoms,
                                  em_state_t *ems)
 {
-    get_f_norm_max(cr, opts, mdatoms, ems->f, &ems->fnorm, &ems->fmax, &ems->a_fmax);
+    get_f_norm_max(cr, opts, mdatoms, as_rvec_array(ems->f.data()),
+                   &ems->fnorm, &ems->fmax, &ems->a_fmax);
 }
 
 //! Initialize the energy minimization
@@ -334,17 +324,15 @@ void init_em(FILE *fplog, const char *title,
              t_commrec *cr, t_inputrec *ir,
              t_state *state_global, gmx_mtop_t *top_global,
              em_state_t *ems, gmx_localtop_t **top,
-             rvec **f,
              t_nrnb *nrnb, rvec mu_tot,
              t_forcerec *fr, gmx_enerdata_t **enerd,
              t_graph **graph, t_mdatoms *mdatoms, gmx_global_stat_t *gstat,
-             gmx_vsite_t *vsite, gmx_constr_t constr,
+             gmx_vsite_t *vsite, gmx_constr_t constr, gmx_shellfc_t **shellfc,
              int nfile, const t_filenm fnm[],
              gmx_mdoutf_t *outf, t_mdebin **mdebin,
              int imdport, unsigned long gmx_unused Flags,
              gmx_wallcycle_t wcycle)
 {
-    int  i;
     real dvdl_constr;
 
     if (fplog)
@@ -355,22 +343,43 @@ void init_em(FILE *fplog, const char *title,
     state_global->ngtc = 0;
 
     /* Initialize lambda variables */
-    initialize_lambdas(fplog, ir, &(state_global->fep_state), state_global->lambda, NULL);
+    initialize_lambdas(fplog, ir, &(state_global->fep_state), &state_global->lambda, NULL);
 
     init_nrnb(nrnb);
 
     /* Interactive molecular dynamics */
-    init_IMD(ir, cr, top_global, fplog, 1, state_global->x,
+    init_IMD(ir, cr, top_global, fplog, 1, as_rvec_array(state_global->x.data()),
              nfile, fnm, NULL, imdport, Flags);
 
+    if (ir->eI == eiNM)
+    {
+        GMX_ASSERT(shellfc != NULL, "With NM we always support shells");
+
+        *shellfc = init_shell_flexcon(stdout,
+                                      top_global,
+                                      n_flexible_constraints(constr),
+                                      ir->nstcalcenergy,
+                                      DOMAINDECOMP(cr));
+    }
+    else
+    {
+        GMX_ASSERT(EI_ENERGY_MINIMIZATION(ir->eI), "This else currently only handles energy minimizers, consider if your algorithm needs shell/flexible-constraint support");
+
+        /* With energy minimization, shells and flexible constraints are
+         * automatically minimized when treated like normal DOFS.
+         */
+        if (shellfc != NULL)
+        {
+            *shellfc = NULL;
+        }
+    }
+
     if (DOMAINDECOMP(cr))
     {
         *top = dd_init_local_top(top_global);
 
         dd_init_local_state(cr->dd, state_global, &ems->s);
 
-        *f = NULL;
-
         /* Distribute the charge groups over the nodes from the master node */
         dd_partition_system(fplog, ir->init_step, cr, TRUE, 1,
                             state_global, top_global, ir,
@@ -383,36 +392,19 @@ void init_em(FILE *fplog, const char *title,
     }
     else
     {
-        snew(*f, top_global->natoms);
-
         /* Just copy the state */
         ems->s = *state_global;
         /* We need to allocate one element extra, since we might use
          * (unaligned) 4-wide SIMD loads to access rvec entries.
          */
-        snew(ems->s.x, ems->s.nalloc + 1);
-        snew(ems->f, ems->s.nalloc+1);
-        snew(ems->s.v, ems->s.nalloc+1);
-        for (i = 0; i < state_global->natoms; i++)
-        {
-            copy_rvec(state_global->x[i], ems->s.x[i]);
-        }
-        copy_mat(state_global->box, ems->s.box);
+        ems->s.x.resize(ems->s.natoms + 1);
+        ems->f.resize(ems->s.natoms + 1);
 
-        *top      = gmx_mtop_generate_local_top(top_global, ir->efep != efepNO);
+        snew(*top, 1);
+        mdAlgorithmsSetupAtomData(cr, ir, top_global, *top, fr,
+                                  graph, mdatoms,
+                                  vsite, shellfc ? *shellfc : NULL);
 
-        setup_bonded_threading(fr, &(*top)->idef);
-
-        if (ir->ePBC != epbcNONE && !fr->bMolPBC)
-        {
-            *graph = mk_graph(fplog, &((*top)->idef), 0, top_global->natoms, FALSE, FALSE);
-        }
-        else
-        {
-            *graph = NULL;
-        }
-
-        atoms2md(top_global, ir, 0, NULL, top_global->natoms, mdatoms);
         update_mdatoms(mdatoms, state_global->lambda[efptFEP]);
 
         if (vsite)
@@ -441,7 +433,10 @@ void init_em(FILE *fplog, const char *title,
             dvdl_constr = 0;
             constrain(PAR(cr) ? NULL : fplog, TRUE, TRUE, constr, &(*top)->idef,
                       ir, cr, -1, 0, 1.0, mdatoms,
-                      ems->s.x, ems->s.x, NULL, fr->bMolPBC, ems->s.box,
+                      as_rvec_array(ems->s.x.data()),
+                      as_rvec_array(ems->s.x.data()),
+                      NULL,
+                      fr->bMolPBC, ems->s.box,
                       ems->s.lambda[efptFEP], &dvdl_constr,
                       NULL, NULL, nrnb, econqCoord);
         }
@@ -473,7 +468,7 @@ void init_em(FILE *fplog, const char *title,
 }
 
 //! Finalize the minimization
-static void finish_em(t_commrec *cr, gmx_mdoutf_t outf,
+static void finish_em(t_commrec *cr, gmx_mdoutf_t outf, const t_inputrec *ir,
                       gmx_walltime_accounting_t walltime_accounting,
                       gmx_wallcycle_t wcycle)
 {
@@ -483,32 +478,21 @@ static void finish_em(t_commrec *cr, gmx_mdoutf_t outf,
         gmx_pme_send_finish(cr);
     }
 
-    done_mdoutf(outf);
+    done_mdoutf(outf, ir);
 
     em_time_end(walltime_accounting, wcycle);
 }
 
 //! Swap two different EM states during minimization
-static void swap_em_state(em_state_t *ems1, em_state_t *ems2)
+static void swap_em_state(em_state_t **ems1, em_state_t **ems2)
 {
-    em_state_t tmp;
+    em_state_t *tmp;
 
     tmp   = *ems1;
     *ems1 = *ems2;
     *ems2 = tmp;
 }
 
-//! Copy coordinate from an EM state to a "normal" state structure
-static void copy_em_coords(em_state_t *ems, t_state *state)
-{
-    int i;
-
-    for (i = 0; (i < state->natoms); i++)
-    {
-        copy_rvec(ems->s.x[i], state->x[i]);
-    }
-}
-
 //! Save the EM trajectory
 static void write_em_traj(FILE *fplog, t_commrec *cr,
                           gmx_mdoutf_t outf,
@@ -516,24 +500,11 @@ static void write_em_traj(FILE *fplog, t_commrec *cr,
                           gmx_mtop_t *top_global,
                           t_inputrec *ir, gmx_int64_t step,
                           em_state_t *state,
-                          t_state *state_global)
+                          t_state *state_global,
+                          energyhistory_t *energyHistory)
 {
-    int      mdof_flags;
-    gmx_bool bIMDout = FALSE;
-
-
-    /* Shall we do IMD output? */
-    if (ir->bIMD)
-    {
-        bIMDout = do_per_step(step, IMD_get_step(ir->imd->setup));
-    }
-
-    if ((bX || bF || bIMDout || confout != NULL) && !DOMAINDECOMP(cr))
-    {
-        copy_em_coords(state, state_global);
-    }
+    int mdof_flags = 0;
 
-    mdof_flags = 0;
     if (bX)
     {
         mdof_flags |= MDOF_X;
@@ -551,7 +522,8 @@ static void write_em_traj(FILE *fplog, t_commrec *cr,
 
     mdoutf_write_to_trajectory_files(fplog, cr, outf, mdof_flags,
                                      top_global, step, (double)step,
-                                     &state->s, state_global, state->f);
+                                     &state->s, state_global, energyHistory,
+                                     &state->f);
 
     if (confout != NULL && MASTER(cr))
     {
@@ -559,12 +531,12 @@ static void write_em_traj(FILE *fplog, t_commrec *cr,
         {
             /* Make molecules whole only for confout writing */
             do_pbc_mtop(fplog, ir->ePBC, state_global->box, top_global,
-                        state_global->x);
+                        as_rvec_array(state_global->x.data()));
         }
 
         write_sto_conf_mtop(confout,
                             *top_global->name, top_global,
-                            state_global->x, NULL, ir->ePBC, state_global->box);
+                            as_rvec_array(state_global->x.data()), NULL, ir->ePBC, state_global->box);
     }
 }
 
@@ -573,7 +545,8 @@ static void write_em_traj(FILE *fplog, t_commrec *cr,
 // \returns true when the step succeeded, false when a constraint error occurred
 static bool do_em_step(t_commrec *cr, t_inputrec *ir, t_mdatoms *md,
                        gmx_bool bMolPBC,
-                       em_state_t *ems1, real a, rvec *f, em_state_t *ems2,
+                       em_state_t *ems1, real a, const PaddedRVecVector *force,
+                       em_state_t *ems2,
                        gmx_constr_t constr, gmx_localtop_t *top,
                        t_nrnb *nrnb, gmx_wallcycle_t wcycle,
                        gmx_int64_t count)
@@ -596,27 +569,28 @@ static bool do_em_step(t_commrec *cr, t_inputrec *ir, t_mdatoms *md,
 
     s2->flags = s1->flags;
 
-    if (s2->nalloc != s1->nalloc)
+    if (s2->natoms != s1->natoms)
     {
-        s2->nalloc = s1->nalloc;
+        s2->natoms = s1->natoms;
         /* We need to allocate one element extra, since we might use
          * (unaligned) 4-wide SIMD loads to access rvec entries.
          */
-        srenew(s2->x, s1->nalloc + 1);
-        srenew(ems2->f,  s1->nalloc);
+        s2->x.resize(s1->natoms + 1);
+        ems2->f.resize(s1->natoms + 1);
         if (s2->flags & (1<<estCGP))
         {
-            srenew(s2->cg_p,  s1->nalloc + 1);
+            s2->cg_p.resize(s1->natoms + 1);
         }
     }
+    if (DOMAINDECOMP(cr) && s2->cg_gl.size() != s1->cg_gl.size())
+    {
+        s2->cg_gl.resize(s1->cg_gl.size());
+    }
 
     s2->natoms = s1->natoms;
     copy_mat(s1->box, s2->box);
     /* Copy free energy state */
-    for (int i = 0; i < efptNR; i++)
-    {
-        s2->lambda[i] = s1->lambda[i];
-    }
+    s2->lambda = s1->lambda;
     copy_mat(s1->box, s2->box);
 
     start = 0;
@@ -626,10 +600,11 @@ static bool do_em_step(t_commrec *cr, t_inputrec *ir, t_mdatoms *md,
     nthreads = gmx_omp_nthreads_get(emntUpdate);
 #pragma omp parallel num_threads(nthreads)
     {
-        rvec *x1 = s1->x;
-        rvec *x2 = s2->x;
+        const rvec *x1 = as_rvec_array(s1->x.data());
+        rvec       *x2 = as_rvec_array(s2->x.data());
+        const rvec *f  = as_rvec_array(force->data());
 
-        int   gf = 0;
+        int         gf = 0;
 #pragma omp for schedule(static) nowait
         for (int i = start; i < end; i++)
         {
@@ -657,8 +632,8 @@ static bool do_em_step(t_commrec *cr, t_inputrec *ir, t_mdatoms *md,
         if (s2->flags & (1<<estCGP))
         {
             /* Copy the CG p vector */
-            rvec *p1 = s1->cg_p;
-            rvec *p2 = s2->cg_p;
+            const rvec *p1 = as_rvec_array(s1->cg_p.data());
+            rvec       *p2 = as_rvec_array(s2->cg_p.data());
 #pragma omp for schedule(static) nowait
             for (int i = start; i < end; i++)
             {
@@ -670,23 +645,10 @@ static bool do_em_step(t_commrec *cr, t_inputrec *ir, t_mdatoms *md,
         if (DOMAINDECOMP(cr))
         {
             s2->ddp_count = s1->ddp_count;
-            if (s2->cg_gl_nalloc < s1->cg_gl_nalloc)
-            {
-#pragma omp barrier
-                s2->cg_gl_nalloc = s1->cg_gl_nalloc;
-                try
-                {
-                    /* We need to allocate one element extra, since we might use
-                     * (unaligned) 4-wide SIMD loads to access rvec entries.
-                     */
-                    srenew(s2->cg_gl, s2->cg_gl_nalloc + 1);
-                }
-                GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
-#pragma omp barrier
-            }
-            s2->ncg_gl = s1->ncg_gl;
+
+            /* OpenMP does not supported unsigned loop variables */
 #pragma omp for schedule(static) nowait
-            for (int i = 0; i < s2->ncg_gl; i++)
+            for (int i = 0; i < static_cast<int>(s2->cg_gl.size()); i++)
             {
                 s2->cg_gl[i] = s1->cg_gl[i];
             }
@@ -701,7 +663,8 @@ static bool do_em_step(t_commrec *cr, t_inputrec *ir, t_mdatoms *md,
         validStep   =
             constrain(NULL, TRUE, TRUE, constr, &top->idef,
                       ir, cr, count, 0, 1.0, md,
-                      s1->x, s2->x, NULL, bMolPBC, s2->box,
+                      as_rvec_array(s1->x.data()), as_rvec_array(s2->x.data()),
+                      NULL, bMolPBC, s2->box,
                       s2->lambda[efptBONDED], &dvdl_constr,
                       NULL, NULL, nrnb, econqCoord);
         wallcycle_stop(wcycle, ewcCONSTR);
@@ -774,7 +737,7 @@ static void evaluate_energy(FILE *fplog, t_commrec *cr,
 
     if (vsite)
     {
-        construct_vsites(vsite, ems->s.x, 1, NULL,
+        construct_vsites(vsite, as_rvec_array(ems->s.x.data()), 1, NULL,
                          top->idef.iparams, top->idef.il,
                          fr->ePBC, fr->bMolPBC, cr, ems->s.box);
     }
@@ -793,9 +756,9 @@ static void evaluate_energy(FILE *fplog, t_commrec *cr,
      */
     do_force(fplog, cr, inputrec,
              count, nrnb, wcycle, top, &top_global->groups,
-             ems->s.box, ems->s.x, &ems->s.hist,
-             ems->f, force_vir, mdatoms, enerd, fcd,
-             ems->s.lambda, graph, fr, vsite, mu_tot, t, NULL, NULL, TRUE,
+             ems->s.box, &ems->s.x, &ems->s.hist,
+             &ems->f, force_vir, mdatoms, enerd, fcd,
+             &ems->s.lambda, graph, fr, vsite, mu_tot, t, NULL, TRUE,
              GMX_FORCE_STATECHANGED | GMX_FORCE_ALLFORCES |
              GMX_FORCE_VIRIAL | GMX_FORCE_ENERGY |
              (bNS ? GMX_FORCE_NS : 0));
@@ -834,9 +797,11 @@ static void evaluate_energy(FILE *fplog, t_commrec *cr,
         /* Project out the constraint components of the force */
         wallcycle_start(wcycle, ewcCONSTR);
         dvdl_constr = 0;
+        rvec *f_rvec = as_rvec_array(ems->f.data());
         constrain(NULL, FALSE, FALSE, constr, &top->idef,
                   inputrec, cr, count, 0, 1.0, mdatoms,
-                  ems->s.x, ems->f, ems->f, fr->bMolPBC, ems->s.box,
+                  as_rvec_array(ems->s.x.data()), f_rvec, f_rvec,
+                  fr->bMolPBC, ems->s.box,
                   ems->s.lambda[efptBONDED], &dvdl_constr,
                   NULL, &shake_vir, nrnb, econqForceDispl);
         enerd->term[F_DVDL_CONSTR] += dvdl_constr;
@@ -852,7 +817,7 @@ static void evaluate_energy(FILE *fplog, t_commrec *cr,
     enerd->term[F_PRES] =
         calc_pres(fr->ePBC, inputrec->nwall, ems->s.box, ekin, vir, pres);
 
-    sum_dhdl(enerd, ems->s.lambda, inputrec->fepvals);
+    sum_dhdl(enerd, &ems->s.lambda, inputrec->fepvals);
 
     if (EI_ENERGY_MINIMIZATION(inputrec->eI))
     {
@@ -865,7 +830,6 @@ static double reorder_partsum(t_commrec *cr, t_grpopts *opts, t_mdatoms *mdatoms
                               gmx_mtop_t *top_global,
                               em_state_t *s_min, em_state_t *s_b)
 {
-    rvec          *fm, *fb, *fmg;
     t_block       *cgs_gl;
     int            ncg, *cg_gl, *index, c, cg, i, a0, a1, a, gf, m;
     double         partsum;
@@ -876,8 +840,8 @@ static double reorder_partsum(t_commrec *cr, t_grpopts *opts, t_mdatoms *mdatoms
         fprintf(debug, "Doing reorder_partsum\n");
     }
 
-    fm = s_min->f;
-    fb = s_b->f;
+    const rvec *fm = as_rvec_array(s_min->f.data());
+    const rvec *fb = as_rvec_array(s_b->f.data());
 
     cgs_gl = dd_charge_groups_global(cr->dd);
     index  = cgs_gl->index;
@@ -886,10 +850,11 @@ static double reorder_partsum(t_commrec *cr, t_grpopts *opts, t_mdatoms *mdatoms
      * This conflicts with the spirit of domain decomposition,
      * but to fully optimize this a much more complicated algorithm is required.
      */
+    rvec *fmg;
     snew(fmg, top_global->natoms);
 
-    ncg   = s_min->s.ncg_gl;
-    cg_gl = s_min->s.cg_gl;
+    ncg   = s_min->s.cg_gl.size();
+    cg_gl = s_min->s.cg_gl.data();
     i     = 0;
     for (c = 0; c < ncg; c++)
     {
@@ -905,8 +870,8 @@ static double reorder_partsum(t_commrec *cr, t_grpopts *opts, t_mdatoms *mdatoms
     gmx_sum(top_global->natoms*3, fmg[0], cr);
 
     /* Now we will determine the part of the sum for the cgs in state s_b */
-    ncg         = s_b->s.ncg_gl;
-    cg_gl       = s_b->s.cg_gl;
+    ncg         = s_b->s.cg_gl.size();
+    cg_gl       = s_b->s.cg_gl.data();
     partsum     = 0;
     i           = 0;
     gf          = 0;
@@ -943,9 +908,7 @@ static real pr_beta(t_commrec *cr, t_grpopts *opts, t_mdatoms *mdatoms,
                     gmx_mtop_t *top_global,
                     em_state_t *s_min, em_state_t *s_b)
 {
-    rvec  *fm, *fb;
     double sum;
-    int    gf, i, m;
 
     /* This is just the classical Polak-Ribiere calculation of beta;
      * it looks a bit complicated since we take freeze groups into account,
@@ -956,20 +919,20 @@ static real pr_beta(t_commrec *cr, t_grpopts *opts, t_mdatoms *mdatoms,
         (s_min->s.ddp_count == cr->dd->ddp_count &&
          s_b->s.ddp_count   == cr->dd->ddp_count))
     {
-        fm  = s_min->f;
-        fb  = s_b->f;
-        sum = 0;
-        gf  = 0;
+        const rvec *fm  = as_rvec_array(s_min->f.data());
+        const rvec *fb  = as_rvec_array(s_b->f.data());
+        sum             = 0;
+        int         gf  = 0;
         /* This part of code can be incorrect with DD,
          * since the atom ordering in s_b and s_min might differ.
          */
-        for (i = 0; i < mdatoms->homenr; i++)
+        for (int i = 0; i < mdatoms->homenr; i++)
         {
             if (mdatoms->cFREEZE)
             {
                 gf = mdatoms->cFREEZE[i];
             }
-            for (m = 0; m < DIM; m++)
+            for (int m = 0; m < DIM; m++)
             {
                 if (!opts->nFreeze[gf][m])
                 {
@@ -995,7 +958,7 @@ namespace gmx
 {
 
 /*! \brief Do conjugate gradients minimization
-    \copydoc integrator_t (FILE *fplog, t_commrec *cr,
+    \copydoc integrator_t(FILE *fplog, t_commrec *cr, const gmx::MDLogger &mdlog,
                            int nfile, const t_filenm fnm[],
                            const gmx_output_env_t *oenv, gmx_bool bVerbose,
                            int nstglobalcomm,
@@ -1015,7 +978,7 @@ namespace gmx
                            unsigned long Flags,
                            gmx_walltime_accounting_t walltime_accounting)
  */
-double do_cg(FILE *fplog, t_commrec *cr,
+double do_cg(FILE *fplog, t_commrec *cr, const gmx::MDLogger gmx_unused &mdlog,
              int nfile, const t_filenm fnm[],
              const gmx_output_env_t gmx_unused *oenv, gmx_bool bVerbose,
              int gmx_unused nstglobalcomm,
@@ -1024,6 +987,7 @@ double do_cg(FILE *fplog, t_commrec *cr,
              t_inputrec *inputrec,
              gmx_mtop_t *top_global, t_fcdata *fcd,
              t_state *state_global,
+             energyhistory_t *energyHistory,
              t_mdatoms *mdatoms,
              t_nrnb *nrnb, gmx_wallcycle_t wcycle,
              gmx_edsam_t gmx_unused ed,
@@ -1037,15 +1001,11 @@ double do_cg(FILE *fplog, t_commrec *cr,
 {
     const char       *CG = "Polak-Ribiere Conjugate Gradients";
 
-    em_state_t       *s_min, *s_a, *s_b, *s_c;
     gmx_localtop_t   *top;
     gmx_enerdata_t   *enerd;
-    rvec             *f;
     gmx_global_stat_t gstat;
     t_graph          *graph;
-    rvec             *p, *sf;
-    double            gpa, gpb, gpc, tmp, minstep;
-    real              fnormn;
+    double            tmp, minstep;
     real              stepsize;
     real              a, b, c, beta = 0.0;
     real              epot_repl = 0;
@@ -1057,19 +1017,22 @@ double do_cg(FILE *fplog, t_commrec *cr,
     tensor            vir, pres;
     int               number_steps, neval = 0, nstcg = inputrec->nstcgsteep;
     gmx_mdoutf_t      outf;
-    int               i, m, gf, step, nminstep;
+    int               m, step, nminstep;
 
     step = 0;
 
-    s_min = init_em_state();
-    s_a   = init_em_state();
-    s_b   = init_em_state();
-    s_c   = init_em_state();
+    /* Create 4 states on the stack and extract pointers that we will swap */
+    em_state_t  s0 {}, s1 {}, s2 {}, s3 {};
+    em_state_t *s_min = &s0;
+    em_state_t *s_a   = &s1;
+    em_state_t *s_b   = &s2;
+    em_state_t *s_c   = &s3;
 
     /* Init em and store the local state in s_min */
     init_em(fplog, CG, cr, inputrec,
-            state_global, top_global, s_min, &top, &f,
-            nrnb, mu_tot, fr, &enerd, &graph, mdatoms, &gstat, vsite, constr,
+            state_global, top_global, s_min, &top,
+            nrnb, mu_tot, fr, &enerd, &graph, mdatoms, &gstat,
+            vsite, constr, NULL,
             nfile, fnm, &outf, &mdebin, imdport, Flags, wcycle);
 
     /* Print to log file */
@@ -1143,11 +1106,11 @@ double do_cg(FILE *fplog, t_commrec *cr,
          */
 
         /* Calculate the new direction in p, and the gradient in this direction, gpa */
-        p   = s_min->s.cg_p;
-        sf  = s_min->f;
-        gpa = 0;
-        gf  = 0;
-        for (i = 0; i < mdatoms->homenr; i++)
+        rvec       *pm  = as_rvec_array(s_min->s.cg_p.data());
+        const rvec *sfm = as_rvec_array(s_min->f.data());
+        double      gpa = 0;
+        int         gf  = 0;
+        for (int i = 0; i < mdatoms->homenr; i++)
         {
             if (mdatoms->cFREEZE)
             {
@@ -1157,13 +1120,13 @@ double do_cg(FILE *fplog, t_commrec *cr,
             {
                 if (!inputrec->opts.nFreeze[gf][m])
                 {
-                    p[i][m] = sf[i][m] + beta*p[i][m];
-                    gpa    -= p[i][m]*sf[i][m];
+                    pm[i][m] = sfm[i][m] + beta*pm[i][m];
+                    gpa     -= pm[i][m]*sfm[i][m];
                     /* f is negative gradient, thus the sign */
                 }
                 else
                 {
-                    p[i][m] = 0;
+                    pm[i][m] = 0;
                 }
             }
         }
@@ -1175,7 +1138,7 @@ double do_cg(FILE *fplog, t_commrec *cr,
         }
 
         /* Calculate the norm of the search vector */
-        get_f_norm_max(cr, &(inputrec->opts), mdatoms, p, &pnorm, NULL, NULL);
+        get_f_norm_max(cr, &(inputrec->opts), mdatoms, pm, &pnorm, NULL, NULL);
 
         /* Just in case stepsize reaches zero due to numerical precision... */
         if (stepsize <= 0)
@@ -1200,7 +1163,7 @@ double do_cg(FILE *fplog, t_commrec *cr,
          * relative change in coordinate is smaller than precision
          */
         minstep = 0;
-        for (i = 0; i < mdatoms->homenr; i++)
+        for (int i = 0; i < mdatoms->homenr; i++)
         {
             for (m = 0; m < DIM; m++)
             {
@@ -1209,7 +1172,7 @@ double do_cg(FILE *fplog, t_commrec *cr,
                 {
                     tmp = 1.0;
                 }
-                tmp      = p[i][m]/tmp;
+                tmp      = pm[i][m]/tmp;
                 minstep += tmp*tmp;
             }
         }
@@ -1233,7 +1196,7 @@ double do_cg(FILE *fplog, t_commrec *cr,
 
         write_em_traj(fplog, cr, outf, do_x, do_f, NULL,
                       top_global, inputrec, step,
-                      s_min, state_global);
+                      s_min, state_global, energyHistory);
 
         /* Take a step downhill.
          * In theory, we should minimize the function along this direction.
@@ -1264,7 +1227,7 @@ double do_cg(FILE *fplog, t_commrec *cr,
         }
 
         /* Take a trial step (new coords in s_c) */
-        do_em_step(cr, inputrec, mdatoms, fr->bMolPBC, s_min, c, s_min->s.cg_p, s_c,
+        do_em_step(cr, inputrec, mdatoms, fr->bMolPBC, s_min, c, &s_min->s.cg_p, s_c,
                    constr, top, nrnb, wcycle, -1);
 
         neval++;
@@ -1276,14 +1239,14 @@ double do_cg(FILE *fplog, t_commrec *cr,
                         mu_tot, enerd, vir, pres, -1, FALSE);
 
         /* Calc derivative along line */
-        p   = s_c->s.cg_p;
-        sf  = s_c->f;
-        gpc = 0;
-        for (i = 0; i < mdatoms->homenr; i++)
+        const rvec *pc  = as_rvec_array(s_c->s.cg_p.data());
+        const rvec *sfc = as_rvec_array(s_c->f.data());
+        double      gpc = 0;
+        for (int i = 0; i < mdatoms->homenr; i++)
         {
             for (m = 0; m < DIM; m++)
             {
-                gpc -= p[i][m]*sf[i][m]; /* f is negative gradient, thus the sign */
+                gpc -= pc[i][m]*sfc[i][m]; /* f is negative gradient, thus the sign */
             }
         }
         /* Sum the gradient along the line across CPUs */
@@ -1336,6 +1299,7 @@ double do_cg(FILE *fplog, t_commrec *cr,
          *
          * If we already found a lower value we just skip this step and continue to the update.
          */
+        double gpb;
         if (!foundlower)
         {
             nminstep = 0;
@@ -1372,7 +1336,7 @@ double do_cg(FILE *fplog, t_commrec *cr,
                 }
 
                 /* Take a trial step to this new point - new coords in s_b */
-                do_em_step(cr, inputrec, mdatoms, fr->bMolPBC, s_min, b, s_min->s.cg_p, s_b,
+                do_em_step(cr, inputrec, mdatoms, fr->bMolPBC, s_min, b, &s_min->s.cg_p, s_b,
                            constr, top, nrnb, wcycle, -1);
 
                 neval++;
@@ -1386,14 +1350,14 @@ double do_cg(FILE *fplog, t_commrec *cr,
                 /* p does not change within a step, but since the domain decomposition
                  * might change, we have to use cg_p of s_b here.
                  */
-                p   = s_b->s.cg_p;
-                sf  = s_b->f;
-                gpb = 0;
-                for (i = 0; i < mdatoms->homenr; i++)
+                const rvec *pb  = as_rvec_array(s_b->s.cg_p.data());
+                const rvec *sfb = as_rvec_array(s_b->f.data());
+                gpb             = 0;
+                for (int i = 0; i < mdatoms->homenr; i++)
                 {
                     for (m = 0; m < DIM; m++)
                     {
-                        gpb -= p[i][m]*sf[i][m]; /* f is negative gradient, thus the sign */
+                        gpb -= pb[i][m]*sfb[i][m]; /* f is negative gradient, thus the sign */
                     }
                 }
                 /* Sum the gradient along the line across CPUs */
@@ -1414,14 +1378,14 @@ double do_cg(FILE *fplog, t_commrec *cr,
                 if (gpb > 0)
                 {
                     /* Replace c endpoint with b */
-                    swap_em_state(s_b, s_c);
+                    swap_em_state(&s_b, &s_c);
                     c   = b;
                     gpc = gpb;
                 }
                 else
                 {
                     /* Replace a endpoint with b */
-                    swap_em_state(s_b, s_a);
+                    swap_em_state(&s_b, &s_a);
                     a   = b;
                     gpa = gpb;
                 }
@@ -1465,7 +1429,7 @@ double do_cg(FILE *fplog, t_commrec *cr,
                     fprintf(debug, "CGE: C (%f) is lower than A (%f), moving C to B\n",
                             s_c->epot, s_a->epot);
                 }
-                swap_em_state(s_b, s_c);
+                swap_em_state(&s_b, &s_c);
                 gpb = gpc;
             }
             else
@@ -1475,7 +1439,7 @@ double do_cg(FILE *fplog, t_commrec *cr,
                     fprintf(debug, "CGE: A (%f) is lower than C (%f), moving A to B\n",
                             s_a->epot, s_c->epot);
                 }
-                swap_em_state(s_b, s_a);
+                swap_em_state(&s_b, &s_a);
                 gpb = gpa;
             }
 
@@ -1487,7 +1451,7 @@ double do_cg(FILE *fplog, t_commrec *cr,
                 fprintf(debug, "CGE: Found a lower energy %f, moving C to B\n",
                         s_c->epot);
             }
-            swap_em_state(s_b, s_c);
+            swap_em_state(&s_b, &s_c);
             gpb = gpc;
         }
 
@@ -1516,7 +1480,7 @@ double do_cg(FILE *fplog, t_commrec *cr,
 
 
         /* update positions */
-        swap_em_state(s_min, s_b);
+        swap_em_state(&s_min, &s_b);
         gpa = gpb;
 
         /* Print it if necessary */
@@ -1551,7 +1515,7 @@ double do_cg(FILE *fplog, t_commrec *cr,
         }
 
         /* Send energies and positions to the IMD client if bIMD is TRUE. */
-        if (do_IMD(inputrec->bIMD, step, cr, TRUE, state_global->box, state_global->x, inputrec, 0, wcycle) && MASTER(cr))
+        if (do_IMD(inputrec->bIMD, step, cr, TRUE, state_global->box, as_rvec_array(state_global->x.data()), inputrec, 0, wcycle) && MASTER(cr))
         {
             IMD_send_positions(inputrec->imd);
         }
@@ -1618,22 +1582,21 @@ double do_cg(FILE *fplog, t_commrec *cr,
 
     write_em_traj(fplog, cr, outf, do_x, do_f, ftp2fn(efSTO, nfile, fnm),
                   top_global, inputrec, step,
-                  s_min, state_global);
+                  s_min, state_global, energyHistory);
 
 
     if (MASTER(cr))
     {
         double sqrtNumAtoms = sqrt(static_cast<double>(state_global->natoms));
-        fnormn = s_min->fnorm/sqrtNumAtoms;
         print_converged(stderr, CG, inputrec->em_tol, step, converged, number_steps,
-                        s_min->epot, s_min->fmax, s_min->a_fmax, fnormn);
+                        s_min, sqrtNumAtoms);
         print_converged(fplog, CG, inputrec->em_tol, step, converged, number_steps,
-                        s_min->epot, s_min->fmax, s_min->a_fmax, fnormn);
+                        s_min, sqrtNumAtoms);
 
         fprintf(fplog, "\nPerformed %d energy evaluations in total.\n", neval);
     }
 
-    finish_em(cr, outf, walltime_accounting, wcycle);
+    finish_em(cr, outf, inputrec, walltime_accounting, wcycle);
 
     /* To print the actual number of steps we needed somewhere */
     walltime_accounting_set_nsteps_done(walltime_accounting, step);
@@ -1643,26 +1606,26 @@ double do_cg(FILE *fplog, t_commrec *cr,
 
 
 /*! \brief Do L-BFGS conjugate gradients minimization
-    \copydoc integrator_t (FILE *fplog, t_commrec *cr,
-                           int nfile, const t_filenm fnm[],
-                           const gmx_output_env_t *oenv, gmx_bool bVerbose,
-                           int nstglobalcomm,
-                           gmx_vsite_t *vsite, gmx_constr_t constr,
-                           int stepout,
-                           t_inputrec *inputrec,
-                           gmx_mtop_t *top_global, t_fcdata *fcd,
-                           t_state *state_global,
-                           t_mdatoms *mdatoms,
-                           t_nrnb *nrnb, gmx_wallcycle_t wcycle,
-                           gmx_edsam_t ed,
-                           t_forcerec *fr,
-                           int repl_ex_nst, int repl_ex_nex, int repl_ex_seed,
-                           real cpt_period, real max_hours,
-                           int imdport,
-                           unsigned long Flags,
-                           gmx_walltime_accounting_t walltime_accounting)
+    \copydoc integrator_t(FILE *fplog, t_commrec *cr, const gmx::MDLogger &mdlog,
+                          int nfile, const t_filenm fnm[],
+                          const gmx_output_env_t *oenv, gmx_bool bVerbose,
+                          int nstglobalcomm,
+                          gmx_vsite_t *vsite, gmx_constr_t constr,
+                          int stepout,
+                          t_inputrec *inputrec,
+                          gmx_mtop_t *top_global, t_fcdata *fcd,
+                          t_state *state_global,
+                          t_mdatoms *mdatoms,
+                          t_nrnb *nrnb, gmx_wallcycle_t wcycle,
+                          gmx_edsam_t ed,
+                          t_forcerec *fr,
+                          int repl_ex_nst, int repl_ex_nex, int repl_ex_seed,
+                          real cpt_period, real max_hours,
+                          int imdport,
+                          unsigned long Flags,
+                          gmx_walltime_accounting_t walltime_accounting)
  */
-double do_lbfgs(FILE *fplog, t_commrec *cr,
+double do_lbfgs(FILE *fplog, t_commrec *cr, const gmx::MDLogger gmx_unused &mdlog,
                 int nfile, const t_filenm fnm[],
                 const gmx_output_env_t gmx_unused *oenv, gmx_bool bVerbose,
                 int gmx_unused nstglobalcomm,
@@ -1671,6 +1634,7 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
                 t_inputrec *inputrec,
                 gmx_mtop_t *top_global, t_fcdata *fcd,
                 t_state *state_global,
+                energyhistory_t *energyHistory,
                 t_mdatoms *mdatoms,
                 t_nrnb *nrnb, gmx_wallcycle_t wcycle,
                 gmx_edsam_t gmx_unused ed,
@@ -1686,25 +1650,22 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
     em_state_t         ems;
     gmx_localtop_t    *top;
     gmx_enerdata_t    *enerd;
-    rvec              *f;
     gmx_global_stat_t  gstat;
     t_graph           *graph;
     int                ncorr, nmaxcorr, point, cp, neval, nminstep;
     double             stepsize, step_taken, gpa, gpb, gpc, tmp, minstep;
-    real              *rho, *alpha, *ff, *xx, *p, *s, *lastx, *lastf, **dx, **dg;
-    real              *xa, *xb, *xc, *fa, *fb, *fc, *xtmp, *ftmp;
+    real              *rho, *alpha, *p, *s, **dx, **dg;
     real               a, b, c, maxdelta, delta;
-    real               diag, Epot0, Epot, EpotA, EpotB, EpotC;
+    real               diag, Epot0;
     real               dgdx, dgdg, sq, yr, beta;
     t_mdebin          *mdebin;
     gmx_bool           converged;
     rvec               mu_tot;
-    real               fnorm, fmax;
     gmx_bool           do_log, do_ene, do_x, do_f, foundlower, *frozen;
     tensor             vir, pres;
     int                start, end, number_steps;
     gmx_mdoutf_t       outf;
-    int                i, k, m, n, nfmax, gf, step;
+    int                i, k, m, n, gf, step;
     int                mdof_flags;
 
     if (PAR(cr))
@@ -1720,23 +1681,9 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
     n        = 3*state_global->natoms;
     nmaxcorr = inputrec->nbfgscorr;
 
-    /* Allocate memory */
-    /* Use pointers to real so we dont have to loop over both atoms and
-     * dimensions all the time...
-     * x/f are allocated as rvec *, so make new x0/f0 pointers-to-real
-     * that point to the same memory.
-     */
-    snew(xa, n);
-    snew(xb, n);
-    snew(xc, n);
-    snew(fa, n);
-    snew(fb, n);
-    snew(fc, n);
     snew(frozen, n);
 
     snew(p, n);
-    snew(lastx, n);
-    snew(lastf, n);
     snew(rho, nmaxcorr);
     snew(alpha, nmaxcorr);
 
@@ -1757,21 +1704,25 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
 
     /* Init em */
     init_em(fplog, LBFGS, cr, inputrec,
-            state_global, top_global, &ems, &top, &f,
-            nrnb, mu_tot, fr, &enerd, &graph, mdatoms, &gstat, vsite, constr,
+            state_global, top_global, &ems, &top,
+            nrnb, mu_tot, fr, &enerd, &graph, mdatoms, &gstat,
+            vsite, constr, NULL,
             nfile, fnm, &outf, &mdebin, imdport, Flags, wcycle);
-    /* Do_lbfgs is not completely updated like do_steep and do_cg,
-     * so we free some memory again.
-     */
-    sfree(ems.s.x);
-    sfree(ems.f);
-
-    xx = (real *)state_global->x;
-    ff = (real *)f;
 
     start = 0;
     end   = mdatoms->homenr;
 
+    /* We need 4 working states */
+    em_state_t  s0 {}, s1 {}, s2 {}, s3 {};
+    em_state_t *sa   = &s0;
+    em_state_t *sb   = &s1;
+    em_state_t *sc   = &s2;
+    em_state_t *last = &s3;
+    /* Initialize by copying the state from ems (we could skip x and f here) */
+    *sa              = ems;
+    *sb              = ems;
+    *sc              = ems;
+
     /* Print to log file */
     print_em_start(fplog, cr, walltime_accounting, wcycle, LBFGS);
 
@@ -1804,7 +1755,7 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
 
     if (vsite)
     {
-        construct_vsites(vsite, state_global->x, 1, NULL,
+        construct_vsites(vsite, as_rvec_array(state_global->x.data()), 1, NULL,
                          top->idef.iparams, top->idef.il,
                          fr->ePBC, fr->bMolPBC, cr, state_global->box);
     }
@@ -1814,8 +1765,6 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
      * We do not unshift, so molecules are always whole
      */
     neval++;
-    ems.s.x = state_global->x;
-    ems.f   = f;
     evaluate_energy(fplog, cr,
                     top_global, &ems, top,
                     inputrec, nrnb, wcycle, gstat,
@@ -1836,13 +1785,6 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
     }
     where();
 
-    /* This is the starting energy */
-    Epot = enerd->term[F_EPOT];
-
-    fnorm = ems.fnorm;
-    fmax  = ems.fmax;
-    nfmax = ems.a_fmax;
-
     /* Set the initial step.
      * since it will be multiplied by the non-normalized search direction
      * vector (force vector the first time), we scale it by the
@@ -1853,13 +1795,13 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
     {
         double sqrtNumAtoms = sqrt(static_cast<double>(state_global->natoms));
         fprintf(stderr, "Using %d BFGS correction steps.\n\n", nmaxcorr);
-        fprintf(stderr, "   F-max             = %12.5e on atom %d\n", fmax, nfmax+1);
-        fprintf(stderr, "   F-Norm            = %12.5e\n", fnorm/sqrtNumAtoms);
+        fprintf(stderr, "   F-max             = %12.5e on atom %d\n", ems.fmax, ems.a_fmax + 1);
+        fprintf(stderr, "   F-Norm            = %12.5e\n", ems.fnorm/sqrtNumAtoms);
         fprintf(stderr, "\n");
         /* and copy to the log file too... */
         fprintf(fplog, "Using %d BFGS correction steps.\n\n", nmaxcorr);
-        fprintf(fplog, "   F-max             = %12.5e on atom %d\n", fmax, nfmax+1);
-        fprintf(fplog, "   F-Norm            = %12.5e\n", fnorm/sqrtNumAtoms);
+        fprintf(fplog, "   F-max             = %12.5e on atom %d\n", ems.fmax, ems.a_fmax + 1);
+        fprintf(fplog, "   F-Norm            = %12.5e\n", ems.fnorm/sqrtNumAtoms);
         fprintf(fplog, "\n");
     }
 
@@ -1867,11 +1809,12 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
     point = 0;
 
     // Set initial search direction to the force (-gradient), or 0 for frozen particles.
+    real *fInit = static_cast<real *>(as_rvec_array(ems.f.data())[0]);
     for (i = 0; i < n; i++)
     {
         if (!frozen[i])
         {
-            dx[point][i] = ff[i]; /* Initial search direction */
+            dx[point][i] = fInit[i]; /* Initial search direction */
         }
         else
         {
@@ -1883,7 +1826,7 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
     // (the main efficiency in the algorithm comes from changing directions), but
     // we still need an initial value, so estimate it as the inverse of the norm
     // so we take small steps where the potential fluctuates a lot.
-    stepsize  = 1.0/fnorm;
+    stepsize  = 1.0/ems.fnorm;
 
     /* Start the loop over BFGS steps.
      * Each successful step is counted, and we continue until
@@ -1918,13 +1861,16 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
         }
 
         mdoutf_write_to_trajectory_files(fplog, cr, outf, mdof_flags,
-                                         top_global, step, (real)step, state_global, state_global, f);
+                                         top_global, step, (real)step, &ems.s, state_global, energyHistory, &ems.f);
 
         /* Do the linesearching in the direction dx[point][0..(n-1)] */
 
         /* make s a pointer to current search direction - point=0 first time we get here */
         s = dx[point];
 
+        real *xx = static_cast<real *>(as_rvec_array(ems.s.x.data())[0]);
+        real *ff = static_cast<real *>(as_rvec_array(ems.f.data())[0]);
+
         // calculate line gradient in position A
         for (gpa = 0, i = 0; i < n; i++)
         {
@@ -1953,17 +1899,12 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
         }
 
         // Before taking any steps along the line, store the old position
-        for (i = 0; i < n; i++)
-        {
-            lastx[i] = xx[i];
-            lastf[i] = ff[i];
-        }
-        Epot0 = Epot;
+        *last       = ems;
+        real *lastx = static_cast<real *>(as_rvec_array(last->s.x.data())[0]);
+        real *lastf = static_cast<real *>(as_rvec_array(last->f.data())[0]);
+        Epot0       = ems.epot;
 
-        for (i = 0; i < n; i++)
-        {
-            xa[i] = xx[i];
-        }
+        *sa         = ems;
 
         /* Take a step downhill.
          * In theory, we should find the actual minimum of the function in this
@@ -1992,7 +1933,6 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
 
         // State "A" is the first position along the line.
         // reference position along line is initially zero
-        EpotA      = Epot0;
         a          = 0.0;
 
         // Check stepsize first. We do not allow displacements
@@ -2023,6 +1963,7 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
         while (maxdelta > inputrec->em_stepsize);
 
         // Take a trial step and move the coordinate array xc[] to position C
+        real *xc = static_cast<real *>(as_rvec_array(sc->s.x.data())[0]);
         for (i = 0; i < n; i++)
         {
             xc[i] = lastx[i] + c*s[i];
@@ -2030,16 +1971,14 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
 
         neval++;
         // Calculate energy for the trial step in position C
-        ems.s.x = (rvec *)xc;
-        ems.f   = (rvec *)fc;
         evaluate_energy(fplog, cr,
-                        top_global, &ems, top,
+                        top_global, sc, top,
                         inputrec, nrnb, wcycle, gstat,
                         vsite, constr, fcd, graph, mdatoms, fr,
                         mu_tot, enerd, vir, pres, step, FALSE);
-        EpotC = ems.epot;
 
         // Calc line gradient in position C
+        real *fc = static_cast<real *>(as_rvec_array(sc->f.data())[0]);
         for (gpc = 0, i = 0; i < n; i++)
         {
             gpc -= s[i]*fc[i]; /* f is negative gradient, thus the sign */
@@ -2053,11 +1992,11 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
         // This is the max amount of increase in energy we tolerate.
         // By allowing VERY small changes (close to numerical precision) we
         // frequently find even better (lower) final energies.
-        tmp = sqrt(GMX_REAL_EPS)*fabs(EpotA);
+        tmp = sqrt(GMX_REAL_EPS)*fabs(sa->epot);
 
         // Accept the step if the energy is lower in the new position C (compared to A),
         // or if it is not significantly higher and the line derivative is still negative.
-        if (EpotC < EpotA || (gpc < 0 && EpotC < (EpotA+tmp)))
+        if (sc->epot < sa->epot || (gpc < 0 && sc->epot < (sa->epot + tmp)))
         {
             // Great, we found a better energy. We no longer try to alter the
             // stepsize, but simply accept this new better position. The we select a new
@@ -2065,7 +2004,6 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
             // to take smaller steps along a line. Set fnorm based on the new C position,
             // which will be used to update the stepsize to 1/fnorm further down.
             foundlower = TRUE;
-            fnorm      = ems.fnorm;
         }
         else
         {
@@ -2090,7 +2028,8 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
             // I also have a safeguard for potentially really pathological functions so we never
             // take more than 20 steps before we give up.
             // If we already found a lower value we just skip this step and continue to the update.
-            nminstep = 0;
+            real fnorm = 0;
+            nminstep   = 0;
             do
             {
                 // Select a new trial point B in the interval [A,C].
@@ -2115,6 +2054,7 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
                 }
 
                 // Take a trial step to point B
+                real *xb = static_cast<real *>(as_rvec_array(sb->s.x.data())[0]);
                 for (i = 0; i < n; i++)
                 {
                     xb[i] = lastx[i] + b*s[i];
@@ -2122,17 +2062,15 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
 
                 neval++;
                 // Calculate energy for the trial step in point B
-                ems.s.x = (rvec *)xb;
-                ems.f   = (rvec *)fb;
                 evaluate_energy(fplog, cr,
-                                top_global, &ems, top,
+                                top_global, sb, top,
                                 inputrec, nrnb, wcycle, gstat,
                                 vsite, constr, fcd, graph, mdatoms, fr,
                                 mu_tot, enerd, vir, pres, step, FALSE);
-                EpotB = ems.epot;
-                fnorm = ems.fnorm;
+                fnorm = sb->fnorm;
 
                 // Calculate gradient in point B
+                real *fb = static_cast<real *>(as_rvec_array(sb->f.data())[0]);
                 for (gpb = 0, i = 0; i < n; i++)
                 {
                     gpb -= s[i]*fb[i]; /* f is negative gradient, thus the sign */
@@ -2149,30 +2087,16 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
                 if (gpb > 0)
                 {
                     /* Replace c endpoint with b */
-                    EpotC = EpotB;
-                    c     = b;
-                    gpc   = gpb;
-                    /* swap coord pointers b/c */
-                    xtmp = xb;
-                    ftmp = fb;
-                    xb   = xc;
-                    fb   = fc;
-                    xc   = xtmp;
-                    fc   = ftmp;
+                    c   = b;
+                    /* swap states b and c */
+                    swap_em_state(&sb, &sc);
                 }
                 else
                 {
                     /* Replace a endpoint with b */
-                    EpotA = EpotB;
-                    a     = b;
-                    gpa   = gpb;
-                    /* swap coord pointers a/b */
-                    xtmp = xb;
-                    ftmp = fb;
-                    xb   = xa;
-                    fb   = fa;
-                    xa   = xtmp;
-                    fa   = ftmp;
+                    a   = b;
+                    /* swap states a and b */
+                    swap_em_state(&sa, &sb);
                 }
 
                 /*
@@ -2182,9 +2106,9 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
                  */
                 nminstep++;
             }
-            while ((EpotB > EpotA || EpotB > EpotC) && (nminstep < 20));
+            while ((sb->epot > sa->epot || sb->epot > sc->epot) && (nminstep < 20));
 
-            if (fabs(EpotB-Epot0) < GMX_REAL_EPS || nminstep >= 20)
+            if (fabs(sb->epot - Epot0) < GMX_REAL_EPS || nminstep >= 20)
             {
                 /* OK. We couldn't find a significantly lower energy.
                  * If ncorr==0 this was steepest descent, and then we give up.
@@ -2213,26 +2137,16 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
 
             /* Select min energy state of A & C, put the best in xx/ff/Epot
              */
-            if (EpotC < EpotA)
+            if (sc->epot < sa->epot)
             {
-                Epot = EpotC;
                 /* Use state C */
-                for (i = 0; i < n; i++)
-                {
-                    xx[i] = xc[i];
-                    ff[i] = fc[i];
-                }
+                ems        = *sc;
                 step_taken = c;
             }
             else
             {
-                Epot = EpotA;
                 /* Use state A */
-                for (i = 0; i < n; i++)
-                {
-                    xx[i] = xa[i];
-                    ff[i] = fa[i];
-                }
+                ems        = *sa;
                 step_taken = a;
             }
 
@@ -2240,13 +2154,8 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
         else
         {
             /* found lower */
-            Epot = EpotC;
             /* Use state C */
-            for (i = 0; i < n; i++)
-            {
-                xx[i] = xc[i];
-                ff[i] = fc[i];
-            }
+            ems        = *sc;
             step_taken = c;
         }
 
@@ -2356,9 +2265,6 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
             }
         }
 
-        /* Test whether the convergence criterion is met */
-        get_f_norm_max(cr, &(inputrec->opts), mdatoms, f, &fnorm, &fmax, &nfmax);
-
         /* Print it if necessary */
         if (MASTER(cr))
         {
@@ -2366,7 +2272,7 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
             {
                 double sqrtNumAtoms = sqrt(static_cast<double>(state_global->natoms));
                 fprintf(stderr, "\rStep %d, Epot=%12.6e, Fnorm=%9.3e, Fmax=%9.3e (atom %d)\n",
-                        step, Epot, fnorm/sqrtNumAtoms, fmax, nfmax+1);
+                        step, ems.epot, ems.fnorm/sqrtNumAtoms, ems.fmax, ems.a_fmax + 1);
                 fflush(stderr);
             }
             /* Store the new (lower) energies */
@@ -2385,18 +2291,18 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
         }
 
         /* Send x and E to IMD client, if bIMD is TRUE. */
-        if (do_IMD(inputrec->bIMD, step, cr, TRUE, state_global->box, state_global->x, inputrec, 0, wcycle) && MASTER(cr))
+        if (do_IMD(inputrec->bIMD, step, cr, TRUE, state_global->box, as_rvec_array(state_global->x.data()), inputrec, 0, wcycle) && MASTER(cr))
         {
             IMD_send_positions(inputrec->imd);
         }
 
         // Reset stepsize in we are doing more iterations
-        stepsize = 1.0/fnorm;
+        stepsize = 1.0/ems.fnorm;
 
         /* Stop when the maximum force lies below tolerance.
          * If we have reached machine precision, converged is already set to true.
          */
-        converged = converged || (fmax < inputrec->em_tol);
+        converged = converged || (ems.fmax < inputrec->em_tol);
 
     }   /* End of the loop */
 
@@ -2408,7 +2314,7 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
         step--; /* we never took that last step in this case */
 
     }
-    if (fmax > inputrec->em_tol)
+    if (ems.fmax > inputrec->em_tol)
     {
         if (MASTER(cr))
         {
@@ -2449,20 +2355,20 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
     do_f = !do_per_step(step, inputrec->nstfout);
     write_em_traj(fplog, cr, outf, do_x, do_f, ftp2fn(efSTO, nfile, fnm),
                   top_global, inputrec, step,
-                  &ems, state_global);
+                  &ems, state_global, energyHistory);
 
     if (MASTER(cr))
     {
         double sqrtNumAtoms = sqrt(static_cast<double>(state_global->natoms));
         print_converged(stderr, LBFGS, inputrec->em_tol, step, converged,
-                        number_steps, Epot, fmax, nfmax, fnorm/sqrtNumAtoms);
+                        number_steps, &ems, sqrtNumAtoms);
         print_converged(fplog, LBFGS, inputrec->em_tol, step, converged,
-                        number_steps, Epot, fmax, nfmax, fnorm/sqrtNumAtoms);
+                        number_steps, &ems, sqrtNumAtoms);
 
         fprintf(fplog, "\nPerformed %d energy evaluations in total.\n", neval);
     }
 
-    finish_em(cr, outf, walltime_accounting, wcycle);
+    finish_em(cr, outf, inputrec, walltime_accounting, wcycle);
 
     /* To print the actual number of steps we needed somewhere */
     walltime_accounting_set_nsteps_done(walltime_accounting, step);
@@ -2471,26 +2377,26 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
 }   /* That's all folks */
 
 /*! \brief Do steepest descents minimization
-    \copydoc integrator_t (FILE *fplog, t_commrec *cr,
-                           int nfile, const t_filenm fnm[],
-                           const gmx_output_env_t *oenv, gmx_bool bVerbose,
-                           int nstglobalcomm,
-                           gmx_vsite_t *vsite, gmx_constr_t constr,
-                           int stepout,
-                           t_inputrec *inputrec,
-                           gmx_mtop_t *top_global, t_fcdata *fcd,
-                           t_state *state_global,
-                           t_mdatoms *mdatoms,
-                           t_nrnb *nrnb, gmx_wallcycle_t wcycle,
-                           gmx_edsam_t ed,
-                           t_forcerec *fr,
-                           int repl_ex_nst, int repl_ex_nex, int repl_ex_seed,
-                           real cpt_period, real max_hours,
-                           int imdport,
-                           unsigned long Flags,
-                           gmx_walltime_accounting_t walltime_accounting)
+    \copydoc integrator_t(FILE *fplog, t_commrec *cr, const gmx::MDLogger &mdlog,
+                          int nfile, const t_filenm fnm[],
+                          const gmx_output_env_t *oenv, gmx_bool bVerbose,
+                          int nstglobalcomm,
+                          gmx_vsite_t *vsite, gmx_constr_t constr,
+                          int stepout,
+                          t_inputrec *inputrec,
+                          gmx_mtop_t *top_global, t_fcdata *fcd,
+                          t_state *state_global,
+                          t_mdatoms *mdatoms,
+                          t_nrnb *nrnb, gmx_wallcycle_t wcycle,
+                          gmx_edsam_t ed,
+                          t_forcerec *fr,
+                          int repl_ex_nst, int repl_ex_nex, int repl_ex_seed,
+                          real cpt_period, real max_hours,
+                          int imdport,
+                          unsigned long Flags,
+                          gmx_walltime_accounting_t walltime_accounting)
  */
-double do_steep(FILE *fplog, t_commrec *cr,
+double do_steep(FILE *fplog, t_commrec *cr, const gmx::MDLogger gmx_unused &mdlog,
                 int nfile, const t_filenm fnm[],
                 const gmx_output_env_t gmx_unused *oenv, gmx_bool bVerbose,
                 int gmx_unused nstglobalcomm,
@@ -2499,6 +2405,7 @@ double do_steep(FILE *fplog, t_commrec *cr,
                 t_inputrec *inputrec,
                 gmx_mtop_t *top_global, t_fcdata *fcd,
                 t_state *state_global,
+                energyhistory_t *energyHistory,
                 t_mdatoms *mdatoms,
                 t_nrnb *nrnb, gmx_wallcycle_t wcycle,
                 gmx_edsam_t gmx_unused  ed,
@@ -2511,14 +2418,12 @@ double do_steep(FILE *fplog, t_commrec *cr,
                 gmx_walltime_accounting_t walltime_accounting)
 {
     const char       *SD = "Steepest Descents";
-    em_state_t       *s_min, *s_try;
     gmx_localtop_t   *top;
     gmx_enerdata_t   *enerd;
-    rvec             *f;
     gmx_global_stat_t gstat;
     t_graph          *graph;
     real              stepsize;
-    real              ustep, fnormn;
+    real              ustep;
     gmx_mdoutf_t      outf;
     t_mdebin         *mdebin;
     gmx_bool          bDone, bAbort, do_x, do_f;
@@ -2528,13 +2433,16 @@ double do_steep(FILE *fplog, t_commrec *cr,
     int               count          = 0;
     int               steps_accepted = 0;
 
-    s_min = init_em_state();
-    s_try = init_em_state();
+    /* Create 2 states on the stack and extract pointers that we will swap */
+    em_state_t  s0 {}, s1 {};
+    em_state_t *s_min = &s0;
+    em_state_t *s_try = &s1;
 
     /* Init em and store the local state in s_try */
     init_em(fplog, SD, cr, inputrec,
-            state_global, top_global, s_try, &top, &f,
-            nrnb, mu_tot, fr, &enerd, &graph, mdatoms, &gstat, vsite, constr,
+            state_global, top_global, s_try, &top,
+            nrnb, mu_tot, fr, &enerd, &graph, mdatoms, &gstat,
+            vsite, constr, NULL,
             nfile, fnm, &outf, &mdebin, imdport, Flags, wcycle);
 
     /* Print to log file  */
@@ -2578,7 +2486,7 @@ double do_steep(FILE *fplog, t_commrec *cr,
         {
             validStep =
                 do_em_step(cr, inputrec, mdatoms, fr->bMolPBC,
-                           s_min, stepsize, s_min->f, s_try,
+                           s_min, stepsize, &s_min->f, s_try,
                            constr, top, nrnb, wcycle, count);
         }
 
@@ -2651,7 +2559,7 @@ double do_steep(FILE *fplog, t_commrec *cr,
             /* Copy the arrays for force, positions and energy  */
             /* The 'Min' array always holds the coords and forces of the minimal
                sampled energy  */
-            swap_em_state(s_min, s_try);
+            swap_em_state(&s_min, &s_try);
             if (count > 0)
             {
                 ustep *= 1.2;
@@ -2662,7 +2570,7 @@ double do_steep(FILE *fplog, t_commrec *cr,
             do_f = do_per_step(steps_accepted, inputrec->nstfout);
             write_em_traj(fplog, cr, outf, do_x, do_f, NULL,
                           top_global, inputrec, count,
-                          s_min, state_global);
+                          s_min, state_global, energyHistory);
         }
         else
         {
@@ -2697,7 +2605,7 @@ double do_steep(FILE *fplog, t_commrec *cr,
         }
 
         /* Send IMD energies and positions, if bIMD is TRUE. */
-        if (do_IMD(inputrec->bIMD, count, cr, TRUE, state_global->box, state_global->x, inputrec, 0, wcycle) && MASTER(cr))
+        if (do_IMD(inputrec->bIMD, count, cr, TRUE, state_global->box, as_rvec_array(state_global->x.data()), inputrec, 0, wcycle) && MASTER(cr))
         {
             IMD_send_positions(inputrec->imd);
         }
@@ -2715,20 +2623,19 @@ double do_steep(FILE *fplog, t_commrec *cr,
     }
     write_em_traj(fplog, cr, outf, TRUE, inputrec->nstfout, ftp2fn(efSTO, nfile, fnm),
                   top_global, inputrec, count,
-                  s_min, state_global);
+                  s_min, state_global, energyHistory);
 
     if (MASTER(cr))
     {
         double sqrtNumAtoms = sqrt(static_cast<double>(state_global->natoms));
-        fnormn = s_min->fnorm/sqrtNumAtoms;
 
         print_converged(stderr, SD, inputrec->em_tol, count, bDone, nsteps,
-                        s_min->epot, s_min->fmax, s_min->a_fmax, fnormn);
+                        s_min, sqrtNumAtoms);
         print_converged(fplog, SD, inputrec->em_tol, count, bDone, nsteps,
-                        s_min->epot, s_min->fmax, s_min->a_fmax, fnormn);
+                        s_min, sqrtNumAtoms);
     }
 
-    finish_em(cr, outf, walltime_accounting, wcycle);
+    finish_em(cr, outf, inputrec, walltime_accounting, wcycle);
 
     /* To print the actual number of steps we needed somewhere */
     inputrec->nsteps = count;
@@ -2739,26 +2646,26 @@ double do_steep(FILE *fplog, t_commrec *cr,
 }   /* That's all folks */
 
 /*! \brief Do normal modes analysis
-    \copydoc integrator_t (FILE *fplog, t_commrec *cr,
-                           int nfile, const t_filenm fnm[],
-                           const gmx_output_env_t *oenv, gmx_bool bVerbose,
-                           int nstglobalcomm,
-                           gmx_vsite_t *vsite, gmx_constr_t constr,
-                           int stepout,
-                           t_inputrec *inputrec,
-                           gmx_mtop_t *top_global, t_fcdata *fcd,
-                           t_state *state_global,
-                           t_mdatoms *mdatoms,
-                           t_nrnb *nrnb, gmx_wallcycle_t wcycle,
-                           gmx_edsam_t ed,
-                           t_forcerec *fr,
-                           int repl_ex_nst, int repl_ex_nex, int repl_ex_seed,
-                           real cpt_period, real max_hours,
-                           int imdport,
-                           unsigned long Flags,
-                           gmx_walltime_accounting_t walltime_accounting)
+    \copydoc integrator_t(FILE *fplog, t_commrec *cr, const gmx::MDLogger &mdlog,
+                          int nfile, const t_filenm fnm[],
+                          const gmx_output_env_t *oenv, gmx_bool bVerbose,
+                          int nstglobalcomm,
+                          gmx_vsite_t *vsite, gmx_constr_t constr,
+                          int stepout,
+                          t_inputrec *inputrec,
+                          gmx_mtop_t *top_global, t_fcdata *fcd,
+                          t_state *state_global,
+                          t_mdatoms *mdatoms,
+                          t_nrnb *nrnb, gmx_wallcycle_t wcycle,
+                          gmx_edsam_t ed,
+                          t_forcerec *fr,
+                          int repl_ex_nst, int repl_ex_nex, int repl_ex_seed,
+                          real cpt_period, real max_hours,
+                          int imdport,
+                          unsigned long Flags,
+                          gmx_walltime_accounting_t walltime_accounting)
  */
-double do_nm(FILE *fplog, t_commrec *cr,
+double do_nm(FILE *fplog, t_commrec *cr, const gmx::MDLogger &mdlog,
              int nfile, const t_filenm fnm[],
              const gmx_output_env_t gmx_unused *oenv, gmx_bool bVerbose,
              int gmx_unused nstglobalcomm,
@@ -2767,6 +2674,7 @@ double do_nm(FILE *fplog, t_commrec *cr,
              t_inputrec *inputrec,
              gmx_mtop_t *top_global, t_fcdata *fcd,
              t_state *state_global,
+             energyhistory_t gmx_unused *energyHistory,
              t_mdatoms *mdatoms,
              t_nrnb *nrnb, gmx_wallcycle_t wcycle,
              gmx_edsam_t  gmx_unused ed,
@@ -2783,7 +2691,6 @@ double do_nm(FILE *fplog, t_commrec *cr,
     int                  nnodes, node;
     gmx_localtop_t      *top;
     gmx_enerdata_t      *enerd;
-    rvec                *f;
     gmx_global_stat_t    gstat;
     t_graph             *graph;
     tensor               vir, pres;
@@ -2793,7 +2700,6 @@ double do_nm(FILE *fplog, t_commrec *cr,
     size_t               sz;
     gmx_sparsematrix_t * sparse_matrix           = NULL;
     real           *     full_matrix             = NULL;
-    em_state_t       *   state_work;
 
     /* added with respect to mdrun */
     int                       row, col;
@@ -2806,25 +2712,17 @@ double do_nm(FILE *fplog, t_commrec *cr,
         gmx_fatal(FARGS, "Constraints present with Normal Mode Analysis, this combination is not supported");
     }
 
-    state_work = init_em_state();
+    gmx_shellfc_t *shellfc;
+
+    em_state_t     state_work {};
 
     /* Init em and store the local state in state_minimum */
     init_em(fplog, NM, cr, inputrec,
-            state_global, top_global, state_work, &top,
-            &f,
-            nrnb, mu_tot, fr, &enerd, &graph, mdatoms, &gstat, vsite, constr,
+            state_global, top_global, &state_work, &top,
+            nrnb, mu_tot, fr, &enerd, &graph, mdatoms, &gstat,
+            vsite, constr, &shellfc,
             nfile, fnm, &outf, NULL, imdport, Flags, wcycle);
 
-    gmx_shellfc_t *shellfc = init_shell_flexcon(stdout,
-                                                top_global,
-                                                n_flexible_constraints(constr),
-                                                inputrec->nstcalcenergy,
-                                                DOMAINDECOMP(cr));
-
-    if (shellfc)
-    {
-        make_local_shells(cr, mdatoms, shellfc);
-    }
     std::vector<size_t> atom_index = get_atom_index(top_global);
     snew(fneg, atom_index.size());
     snew(dfdx, atom_index.size());
@@ -2848,17 +2746,18 @@ double do_nm(FILE *fplog, t_commrec *cr,
      */
     if (EEL_FULL(fr->eeltype) || fr->rlist == 0.0)
     {
-        md_print_info(cr, fplog, "Non-cutoff electrostatics used, forcing full Hessian format.\n");
+        GMX_LOG(mdlog.warning).appendText("Non-cutoff electrostatics used, forcing full Hessian format.");
         bSparse = FALSE;
     }
     else if (atom_index.size() < 1000)
     {
-        md_print_info(cr, fplog, "Small system size (N=%d), using full Hessian format.\n", atom_index.size());
+        GMX_LOG(mdlog.warning).appendTextFormatted("Small system size (N=%d), using full Hessian format.",
+                                                   atom_index.size());
         bSparse = FALSE;
     }
     else
     {
-        md_print_info(cr, fplog, "Using compressed symmetric sparse Hessian format.\n");
+        GMX_LOG(mdlog.warning).appendText("Using compressed symmetric sparse Hessian format.");
         bSparse = TRUE;
     }
 
@@ -2898,23 +2797,23 @@ double do_nm(FILE *fplog, t_commrec *cr,
     /* Make evaluate_energy do a single node force calculation */
     cr->nnodes = 1;
     evaluate_energy(fplog, cr,
-                    top_global, state_work, top,
+                    top_global, &state_work, top,
                     inputrec, nrnb, wcycle, gstat,
                     vsite, constr, fcd, graph, mdatoms, fr,
                     mu_tot, enerd, vir, pres, -1, TRUE);
     cr->nnodes = nnodes;
 
     /* if forces are not small, warn user */
-    get_state_f_norm_max(cr, &(inputrec->opts), mdatoms, state_work);
+    get_state_f_norm_max(cr, &(inputrec->opts), mdatoms, &state_work);
 
-    md_print_info(cr, fplog, "Maximum force:%12.5e\n", state_work->fmax);
-    if (state_work->fmax > 1.0e-3)
+    GMX_LOG(mdlog.warning).appendTextFormatted("Maximum force:%12.5e", state_work.fmax);
+    if (state_work.fmax > 1.0e-3)
     {
-        md_print_info(cr, fplog,
-                      "The force is probably not small enough to "
-                      "ensure that you are at a minimum.\n"
-                      "Be aware that negative eigenvalues may occur\n"
-                      "when the resulting matrix is diagonalized.\n\n");
+        GMX_LOG(mdlog.warning).appendText(
+                "The force is probably not small enough to "
+                "ensure that you are at a minimum.\n"
+                "Be aware that negative eigenvalues may occur\n"
+                "when the resulting matrix is diagonalized.");
     }
 
     /***********************************************************
@@ -2938,17 +2837,17 @@ double do_nm(FILE *fplog, t_commrec *cr,
             int         force_flags = GMX_FORCE_STATECHANGED | GMX_FORCE_ALLFORCES;
             double      t           = 0;
 
-            x_min = state_work->s.x[atom][d];
+            x_min = state_work.s.x[atom][d];
 
             for (unsigned int dx = 0; (dx < 2); dx++)
             {
                 if (dx == 0)
                 {
-                    state_work->s.x[atom][d] = x_min - der_range;
+                    state_work.s.x[atom][d] = x_min - der_range;
                 }
                 else
                 {
-                    state_work->s.x[atom][d] = x_min + der_range;
+                    state_work.s.x[atom][d] = x_min + der_range;
                 }
 
                 /* Make evaluate_energy do a single node force calculation */
@@ -2960,17 +2859,17 @@ double do_nm(FILE *fplog, t_commrec *cr,
                                                inputrec, bNS, force_flags,
                                                top,
                                                constr, enerd, fcd,
-                                               &state_work->s, state_work->f, vir, mdatoms,
+                                               &state_work.s, &state_work.f, vir, mdatoms,
                                                nrnb, wcycle, graph, &top_global->groups,
                                                shellfc, fr, bBornRadii, t, mu_tot,
-                                               vsite, NULL);
+                                               vsite);
                     bNS = false;
                     step++;
                 }
                 else
                 {
                     evaluate_energy(fplog, cr,
-                                    top_global, state_work, top,
+                                    top_global, &state_work, top,
                                     inputrec, nrnb, wcycle, gstat,
                                     vsite, constr, fcd, graph, mdatoms, fr,
                                     mu_tot, enerd, vir, pres, atom*2+dx, FALSE);
@@ -2982,20 +2881,20 @@ double do_nm(FILE *fplog, t_commrec *cr,
                 {
                     for (size_t i = 0; i < atom_index.size(); i++)
                     {
-                        copy_rvec(state_work->f[atom_index[i]], fneg[i]);
+                        copy_rvec(state_work.f[atom_index[i]], fneg[i]);
                     }
                 }
             }
 
             /* x is restored to original */
-            state_work->s.x[atom][d] = x_min;
+            state_work.s.x[atom][d] = x_min;
 
             for (size_t j = 0; j < atom_index.size(); j++)
             {
                 for (size_t k = 0; (k < DIM); k++)
                 {
                     dfdx[j][k] =
-                        -(state_work->f[atom_index[j]][k] - fneg[j][k])/(2*der_range);
+                        -(state_work.f[atom_index[j]][k] - fneg[j][k])/(2*der_range);
                 }
             }
 
@@ -3067,7 +2966,7 @@ double do_nm(FILE *fplog, t_commrec *cr,
         gmx_mtxio_write(ftp2fn(efMTX, nfile, fnm), sz, sz, full_matrix, sparse_matrix);
     }
 
-    finish_em(cr, outf, walltime_accounting, wcycle);
+    finish_em(cr, outf, inputrec, walltime_accounting, wcycle);
 
     walltime_accounting_set_nsteps_done(walltime_accounting, atom_index.size()*2);
 
index 39464192315a153f2931594c615d404cce44c7ff..3f62e86de485c915adab7a05a8c6ce9bfb67ee8c 100644 (file)
@@ -434,8 +434,8 @@ void nbnxn_gpu_launch_kernel(gmx_nbnxn_cuda_t       *nb,
 
     if (debug)
     {
-        fprintf(debug, "GPU launch configuration:\n\tThread block: %dx%dx%d\n\t"
-                "\tGrid: %dx%d\n\t#Super-clusters/clusters: %d/%d (%d)\n"
+        fprintf(debug, "GPU launch configuration:\n\tThread block: %ux%ux%u\n\t"
+                "\tGrid: %ux%u\n\t#Super-clusters/clusters: %d/%d (%d)\n"
                 "\tShMem: %d\n",
                 dim_block.x, dim_block.y, dim_block.z,
                 dim_grid.x, dim_grid.y, plist->nsci*c_numClPerSupercl,
index 846a281037a762a79ffd16910a90d619da019aba..62f5cc96a8f5c4e531c832c961a69754d83d721e 100644 (file)
                 {
                     real skipmask_rvdw;
 
-                    skipmask_rvdw = (rsq < rvdw2);
+                    skipmask_rvdw = (rsq < rvdw2) ? 1.0 : 0.0;
                     frLJ         *= skipmask_rvdw;
 #ifdef CALC_ENERGIES
                     VLJ    *= skipmask_rvdw;
index 98b3a3324411081f70daec3b438a4815b2a95234..a5ad681b1844a7451ae195047f81f1627592ccee 100644 (file)
@@ -65,6 +65,7 @@
 #include "gromacs/mdtypes/nblist.h"
 #include "gromacs/pbcutil/ishift.h"
 #include "gromacs/pbcutil/pbc.h"
+#include "gromacs/topology/mtop_lookup.h"
 #include "gromacs/topology/mtop_util.h"
 #include "gromacs/topology/topology.h"
 #include "gromacs/utility/fatalerror.h"
@@ -315,32 +316,25 @@ static void init_QMrec(int grpnr, t_QMrec *qm, int nr, int *atomarray,
 {
     /* fills the t_QMrec struct of QM group grpnr
      */
-    int                   i;
-    gmx_mtop_atomlookup_t alook;
-    t_atom               *atom;
-
 
     qm->nrQMatoms = nr;
     snew(qm->xQM, nr);
     snew(qm->indexQM, nr);
     snew(qm->shiftQM, nr); /* the shifts */
-    for (i = 0; i < nr; i++)
+    for (int i = 0; i < nr; i++)
     {
         qm->indexQM[i] = atomarray[i];
     }
 
-    alook = gmx_mtop_atomlookup_init(mtop);
-
     snew(qm->atomicnumberQM, nr);
-    for (i = 0; i < qm->nrQMatoms; i++)
+    int molb = 0;
+    for (int i = 0; i < qm->nrQMatoms; i++)
     {
-        gmx_mtop_atomnr_to_atom(alook, qm->indexQM[i], &atom);
-        qm->nelectrons       += mtop->atomtypes.atomnumber[atom->type];
-        qm->atomicnumberQM[i] = mtop->atomtypes.atomnumber[atom->type];
+        const t_atom &atom = mtopGetAtomParameters(mtop, qm->indexQM[i], &molb);
+        qm->nelectrons       += mtop->atomtypes.atomnumber[atom.type];
+        qm->atomicnumberQM[i] = mtop->atomtypes.atomnumber[atom.type];
     }
 
-    gmx_mtop_atomlookup_destroy(alook);
-
     qm->QMcharge       = ir->opts.QMcharge[grpnr];
     qm->multiplicity   = ir->opts.QMmult[grpnr];
     qm->nelectrons    -= ir->opts.QMcharge[grpnr];
@@ -468,11 +462,9 @@ void init_QMMMrec(t_commrec  *cr,
     t_iatom                 *iatoms;
     real                     c12au, c6au;
     gmx_mtop_atomloop_all_t  aloop;
-    t_atom                  *atom;
     gmx_mtop_ilistloop_all_t iloop;
     int                      a_offset;
     t_ilist                 *ilist_mol;
-    gmx_mtop_atomlookup_t    alook;
 
     if (ir->cutoff_scheme != ecutsGROUP)
     {
@@ -535,6 +527,7 @@ void init_QMMMrec(t_commrec  *cr,
     {
         /* new layer */
         aloop = gmx_mtop_atomloop_all_init(mtop);
+        const t_atom *atom;
         while (gmx_mtop_atomloop_all_next(aloop, &i, &atom))
         {
             if (qm_nr >= qm_max)
@@ -661,15 +654,17 @@ void init_QMMMrec(t_commrec  *cr,
 
         /* standard QMMM, all layers are merged together so there is one QM
          * subsystem and one MM subsystem.
-         * Also we set the charges to zero in the md->charge arrays to prevent
-         * the innerloops from doubly counting the electostatic QM MM interaction
+         * Also we set the charges to zero in mtop to prevent the innerloops
+         * from doubly counting the electostatic QM MM interaction
+         * TODO: Consider doing this in grompp instead.
          */
 
-        alook = gmx_mtop_atomlookup_init(mtop);
-
+        int molb = 0;
         for (k = 0; k < qm_nr; k++)
         {
-            gmx_mtop_atomnr_to_atom(alook, qm_arr[k], &atom);
+            int     indexInMolecule;
+            mtopGetMolblockIndex(mtop, qm_arr[k], &molb, NULL, &indexInMolecule);
+            t_atom *atom = &mtop->moltype[mtop->molblock[molb].type].atoms.atom[indexInMolecule];
             atom->q  = 0.0;
             atom->qB = 0.0;
         }
@@ -681,10 +676,10 @@ void init_QMMMrec(t_commrec  *cr,
         {
             for (i = 0; i < qm_nr; i++)
             {
-                gmx_mtop_atomnr_to_atom(alook, qm_arr[i], &atom);
+                const t_atom &atom = mtopGetAtomParameters(mtop, qm_arr[i], &molb);
                 /* nbfp now includes the 6.0/12.0 derivative prefactors */
-                qr->qm[0]->c6[i]  =  C6(fr->nbfp, mtop->ffparams.atnr, atom->type, atom->type)/c6au/6.0;
-                qr->qm[0]->c12[i] = C12(fr->nbfp, mtop->ffparams.atnr, atom->type, atom->type)/c12au/12.0;
+                qr->qm[0]->c6[i]   =  C6(fr->nbfp, mtop->ffparams.atnr, atom.type, atom.type)/c6au/6.0;
+                qr->qm[0]->c12[i]  = C12(fr->nbfp, mtop->ffparams.atnr, atom.type, atom.type)/c12au/12.0;
             }
         }
 
@@ -692,9 +687,10 @@ void init_QMMMrec(t_commrec  *cr,
          */
         for (i = 0; i < qm_nr; i++)
         {
-            gmx_mtop_atomnr_to_ilist(alook, qm_arr[i], &ilist_mol, &a_offset);
-            nrvsite2 = ilist_mol[F_VSITE2].nr;
-            iatoms   = ilist_mol[F_VSITE2].iatoms;
+            mtopGetMolblockIndex(mtop, qm_arr[i], &molb, NULL, &a_offset);
+            ilist_mol = mtop->moltype[mtop->molblock[molb].type].ilist;
+            nrvsite2  = ilist_mol[F_VSITE2].nr;
+            iatoms    = ilist_mol[F_VSITE2].iatoms;
 
             for (k = 0; k < nrvsite2; k += 4)
             {
@@ -722,8 +718,6 @@ void init_QMMMrec(t_commrec  *cr,
             }
         }
 
-        gmx_mtop_atomlookup_destroy(alook);
-
         /* MM rec creation */
         mm               = mk_MMrec();
         mm->scalefactor  = ir->scalefactor;
index c62ae769c199ccc731b53c417044eb923535625a..a92d32503f76bbbe9979b6dd14eeef46ed148e7e 100644 (file)
@@ -64,6 +64,7 @@
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/pbcutil/mshift.h"
 #include "gromacs/pbcutil/pbc.h"
+#include "gromacs/topology/mtop_lookup.h"
 #include "gromacs/topology/mtop_util.h"
 #include "gromacs/utility/arraysize.h"
 #include "gromacs/utility/cstringutil.h"
@@ -83,6 +84,7 @@ typedef struct {
 } t_shell;
 
 struct gmx_shellfc_t {
+    /* Shell counts, indices, parameters and working data */
     int          nshell_gl;              /* The number of shells in the system        */
     t_shell     *shell_gl;               /* All the shells (for DD only)              */
     int         *shell_index_gl;         /* Global shell index (for DD only)          */
@@ -93,9 +95,12 @@ struct gmx_shellfc_t {
     gmx_bool     bPredict;               /* Predict shell positions                   */
     gmx_bool     bRequireInit;           /* Require initialization of shell positions */
     int          nflexcon;               /* The number of flexible constraints        */
-    rvec        *x[2];                   /* Array for iterative minimization          */
-    rvec        *f[2];                   /* Array for iterative minimization          */
-    int          x_nalloc;               /* The allocation size of x and f            */
+
+    /* Temporary arrays, should be fixed size 2 when fully converted to C++ */
+    PaddedRVecVector *x;                 /* Array for iterative minimization          */
+    PaddedRVecVector *f;                 /* Array for iterative minimization          */
+
+    /* Flexible constraint working data */
     rvec        *acc_dir;                /* Acceleration direction for flexcon        */
     rvec        *x_old;                  /* Old coordinates for flexcon               */
     int          flex_nalloc;            /* The allocation size of acc_dir and x_old  */
@@ -146,13 +151,6 @@ static void predict_shells(FILE *fplog, rvec x[], rvec v[], real dt,
     int                   i, m, s1, n1, n2, n3;
     real                  dt_1, fudge, tm, m1, m2, m3;
     rvec                 *ptr;
-    gmx_mtop_atomlookup_t alook = NULL;
-    t_atom               *atom;
-
-    if (mass == NULL)
-    {
-        alook = gmx_mtop_atomlookup_init(mtop);
-    }
 
     /* We introduce a fudge factor for performance reasons: with this choice
      * the initial force on the shells is about a factor of two lower than
@@ -175,6 +173,7 @@ static void predict_shells(FILE *fplog, rvec x[], rvec v[], real dt,
         dt_1 = fudge*dt;
     }
 
+    int molb = 0;
     for (i = 0; (i < ns); i++)
     {
         s1 = s[i].shell;
@@ -202,10 +201,8 @@ static void predict_shells(FILE *fplog, rvec x[], rvec v[], real dt,
                 else
                 {
                     /* Not the correct masses with FE, but it is just a prediction... */
-                    gmx_mtop_atomnr_to_atom(alook, n1, &atom);
-                    m1 = atom->m;
-                    gmx_mtop_atomnr_to_atom(alook, n2, &atom);
-                    m2 = atom->m;
+                    m1 = mtopGetAtomMass(mtop, n1, &molb);
+                    m2 = mtopGetAtomMass(mtop, n2, &molb);
                 }
                 tm = dt_1/(m1+m2);
                 for (m = 0; (m < DIM); m++)
@@ -226,12 +223,9 @@ static void predict_shells(FILE *fplog, rvec x[], rvec v[], real dt,
                 else
                 {
                     /* Not the correct masses with FE, but it is just a prediction... */
-                    gmx_mtop_atomnr_to_atom(alook, n1, &atom);
-                    m1 = atom->m;
-                    gmx_mtop_atomnr_to_atom(alook, n2, &atom);
-                    m2 = atom->m;
-                    gmx_mtop_atomnr_to_atom(alook, n3, &atom);
-                    m3 = atom->m;
+                    m1 = mtopGetAtomMass(mtop, n1, &molb);
+                    m2 = mtopGetAtomMass(mtop, n2, &molb);
+                    m3 = mtopGetAtomMass(mtop, n3, &molb);
                 }
                 tm = dt_1/(m1+m2+m3);
                 for (m = 0; (m < DIM); m++)
@@ -243,11 +237,6 @@ static void predict_shells(FILE *fplog, rvec x[], rvec v[], real dt,
                 gmx_fatal(FARGS, "Shell %d has %d nuclei!", i, s[i].nnucl);
         }
     }
-
-    if (mass == NULL)
-    {
-        gmx_mtop_atomlookup_destroy(alook);
-    }
 }
 
 /*! \brief Count the different particle types in a system
@@ -270,7 +259,7 @@ static std::array<int, eptNR> countPtypes(FILE       *fplog,
 
     gmx_mtop_atomloop_block_t  aloopb = gmx_mtop_atomloop_block_init(mtop);
     int                        nmol;
-    t_atom                    *atom;
+    const t_atom              *atom;
     while (gmx_mtop_atomloop_block_next(aloopb, &atom, &nmol))
     {
         switch (atom->ptype)
@@ -309,7 +298,7 @@ gmx_shellfc_t *init_shell_flexcon(FILE *fplog,
     gmx_shellfc_t            *shfc;
     t_shell                  *shell;
     int                      *shell_index = NULL, *at2cg;
-    t_atom                   *atom;
+    const t_atom             *atom;
 
     int                       ns, nshell, nsi;
     int                       i, j, type, mb, a_offset, cg, mol, ftype, nra;
@@ -334,6 +323,8 @@ gmx_shellfc_t *init_shell_flexcon(FILE *fplog,
     }
 
     snew(shfc, 1);
+    shfc->x        = new PaddedRVecVector[2] {};
+    shfc->f        = new PaddedRVecVector[2] {};
     shfc->nflexcon = nflexcon;
 
     if (nshell == 0)
@@ -666,7 +657,7 @@ void make_local_shells(t_commrec *cr, t_mdatoms *md,
     shfc->shell  = shell;
 }
 
-static void do_1pos(rvec xnew, rvec xold, rvec f, real step)
+static void do_1pos(rvec xnew, const rvec xold, const rvec f, real step)
 {
     real xo, yo, zo;
     real dx, dy, dz;
@@ -684,7 +675,7 @@ static void do_1pos(rvec xnew, rvec xold, rvec f, real step)
     xnew[ZZ] = zo+dz;
 }
 
-static void do_1pos3(rvec xnew, rvec xold, rvec f, rvec step)
+static void do_1pos3(rvec xnew, const rvec xold, const rvec f, const rvec step)
 {
     real xo, yo, zo;
     real dx, dy, dz;
@@ -702,18 +693,21 @@ static void do_1pos3(rvec xnew, rvec xold, rvec f, rvec step)
     xnew[ZZ] = zo+dz;
 }
 
-static void directional_sd(rvec xold[], rvec xnew[], rvec acc_dir[],
-                           int start, int homenr, real step)
+static void directional_sd(const PaddedRVecVector *xold, PaddedRVecVector *xnew, const rvec acc_dir[],
+                           int homenr, real step)
 {
-    int  i;
+    const rvec *xo = as_rvec_array(xold->data());
+    rvec       *xn = as_rvec_array(xnew->data());
 
-    for (i = start; i < homenr; i++)
+    for (int i = 0; i < homenr; i++)
     {
-        do_1pos(xnew[i], xold[i], acc_dir[i], step);
+        do_1pos(xn[i], xo[i], acc_dir[i], step);
     }
 }
 
-static void shell_pos_sd(rvec xcur[], rvec xnew[], rvec f[],
+static void shell_pos_sd(const PaddedRVecVector * gmx_restrict xcur,
+                         PaddedRVecVector * gmx_restrict xnew,
+                         const PaddedRVecVector *f,
                          int ns, t_shell s[], int count)
 {
     const real step_scale_min       = 0.8,
@@ -747,8 +741,8 @@ static void shell_pos_sd(rvec xcur[], rvec xnew[], rvec f[],
         {
             for (d = 0; d < DIM; d++)
             {
-                dx = xcur[shell][d] - s[i].xold[d];
-                df =    f[shell][d] - s[i].fold[d];
+                dx = (*xcur)[shell][d] - s[i].xold[d];
+                df =    (*f)[shell][d] - s[i].fold[d];
                 /* -dx/df gets used to generate an interpolated value, but would
                  * cause a NaN if df were binary-equal to zero. Values close to
                  * zero won't cause problems (because of the min() and max()), so
@@ -782,18 +776,18 @@ static void shell_pos_sd(rvec xcur[], rvec xnew[], rvec f[],
 #endif
             }
         }
-        copy_rvec(xcur[shell], s[i].xold);
-        copy_rvec(f[shell],   s[i].fold);
+        copy_rvec((*xcur)[shell], s[i].xold);
+        copy_rvec((*f)[shell],   s[i].fold);
 
-        do_1pos3(xnew[shell], xcur[shell], f[shell], s[i].step);
+        do_1pos3((*xnew)[shell], (*xcur)[shell], (*f)[shell], s[i].step);
 
         if (gmx_debug_at)
         {
             fprintf(debug, "shell[%d] = %d\n", i, shell);
-            pr_rvec(debug, 0, "fshell", f[shell], DIM, TRUE);
-            pr_rvec(debug, 0, "xold", xcur[shell], DIM, TRUE);
+            pr_rvec(debug, 0, "fshell", (*f)[shell], DIM, TRUE);
+            pr_rvec(debug, 0, "xold", (*xcur)[shell], DIM, TRUE);
             pr_rvec(debug, 0, "step", s[i].step, DIM, TRUE);
-            pr_rvec(debug, 0, "xnew", xnew[shell], DIM, TRUE);
+            pr_rvec(debug, 0, "xnew", (*xnew)[shell], DIM, TRUE);
         }
     }
 #ifdef PRINT_STEP
@@ -829,19 +823,19 @@ static void print_epot(FILE *fp, gmx_int64_t mdstep, int count, real epot, real
 }
 
 
-static real rms_force(t_commrec *cr, rvec f[], int ns, t_shell s[],
+static real rms_force(t_commrec *cr, const PaddedRVecVector *force, int ns, t_shell s[],
                       int ndir, real *sf_dir, real *Epot)
 {
-    int    i, shell, ntot;
-    double buf[4];
+    double      buf[4];
+    const rvec *f = as_rvec_array(force->data());
 
     buf[0] = *sf_dir;
-    for (i = 0; i < ns; i++)
+    for (int i = 0; i < ns; i++)
     {
-        shell    = s[i].shell;
-        buf[0]  += norm2(f[shell]);
+        int shell  = s[i].shell;
+        buf[0]    += norm2(f[shell]);
     }
-    ntot = ns;
+    int ntot = ns;
 
     if (PAR(cr))
     {
@@ -858,7 +852,7 @@ static real rms_force(t_commrec *cr, rvec f[], int ns, t_shell s[],
     return (ntot ? std::sqrt(buf[0]/ntot) : 0);
 }
 
-static void check_pbc(FILE *fp, rvec x[], int shell)
+static void check_pbc(FILE *fp, PaddedRVecVector x, int shell)
 {
     int m, now;
 
@@ -867,13 +861,13 @@ static void check_pbc(FILE *fp, rvec x[], int shell)
     {
         if (fabs(x[shell][m]-x[now][m]) > 0.3)
         {
-            pr_rvecs(fp, 0, "SHELL-X", x+now, 5);
+            pr_rvecs(fp, 0, "SHELL-X", as_rvec_array(x.data())+now, 5);
             break;
         }
     }
 }
 
-static void dump_shells(FILE *fp, rvec x[], rvec f[], real ftol, int ns, t_shell s[])
+static void dump_shells(FILE *fp, PaddedRVecVector x, PaddedRVecVector f, real ftol, int ns, t_shell s[])
 {
     int  i, shell;
     real ft2, ff2;
@@ -896,11 +890,12 @@ static void dump_shells(FILE *fp, rvec x[], rvec f[], real ftol, int ns, t_shell
 static void init_adir(FILE *log, gmx_shellfc_t *shfc,
                       gmx_constr_t constr, t_idef *idef, t_inputrec *ir,
                       t_commrec *cr, int dd_ac1,
-                      gmx_int64_t step, t_mdatoms *md, int start, int end,
+                      gmx_int64_t step, t_mdatoms *md, int end,
                       rvec *x_old, rvec *x_init, rvec *x,
                       rvec *f, rvec *acc_dir,
                       gmx_bool bMolPBC, matrix box,
-                      real *lambda, real *dvdlambda, t_nrnb *nrnb)
+                      const std::vector<real> *lambda, real *dvdlambda,
+                      t_nrnb *nrnb)
 {
     rvec           *xnold, *xnew;
     double          dt, w_dt;
@@ -913,7 +908,7 @@ static void init_adir(FILE *log, gmx_shellfc_t *shfc,
     }
     else
     {
-        n = end - start;
+        n = end;
     }
     if (n > shfc->adir_nalloc)
     {
@@ -929,7 +924,7 @@ static void init_adir(FILE *log, gmx_shellfc_t *shfc,
     dt = ir->delta_t;
 
     /* Does NOT work with freeze or acceleration groups (yet) */
-    for (n = start; n < end; n++)
+    for (n = 0; n < end; n++)
     {
         w_dt = md->invmass[n]*dt;
 
@@ -937,31 +932,31 @@ static void init_adir(FILE *log, gmx_shellfc_t *shfc,
         {
             if ((ptype[n] != eptVSite) && (ptype[n] != eptShell))
             {
-                xnold[n-start][d] = x[n][d] - (x_init[n][d] - x_old[n][d]);
-                xnew[n-start][d]  = 2*x[n][d] - x_old[n][d] + f[n][d]*w_dt*dt;
+                xnold[n][d] = x[n][d] - (x_init[n][d] - x_old[n][d]);
+                xnew[n][d]  = 2*x[n][d] - x_old[n][d] + f[n][d]*w_dt*dt;
             }
             else
             {
-                xnold[n-start][d] = x[n][d];
-                xnew[n-start][d]  = x[n][d];
+                xnold[n][d] = x[n][d];
+                xnew[n][d]  = x[n][d];
             }
         }
     }
     constrain(log, FALSE, FALSE, constr, idef, ir, cr, step, 0, 1.0, md,
-              x, xnold-start, NULL, bMolPBC, box,
-              lambda[efptBONDED], &(dvdlambda[efptBONDED]),
+              x, xnold, NULL, bMolPBC, box,
+              (*lambda)[efptBONDED], &(dvdlambda[efptBONDED]),
               NULL, NULL, nrnb, econqCoord);
     constrain(log, FALSE, FALSE, constr, idef, ir, cr, step, 0, 1.0, md,
-              x, xnew-start, NULL, bMolPBC, box,
-              lambda[efptBONDED], &(dvdlambda[efptBONDED]),
+              x, xnew, NULL, bMolPBC, box,
+              (*lambda)[efptBONDED], &(dvdlambda[efptBONDED]),
               NULL, NULL, nrnb, econqCoord);
 
-    for (n = start; n < end; n++)
+    for (n = 0; n < end; n++)
     {
         for (d = 0; d < DIM; d++)
         {
-            xnew[n-start][d] =
-                -(2*x[n][d]-xnold[n-start][d]-xnew[n-start][d])/gmx::square(dt)
+            xnew[n][d] =
+                -(2*x[n][d]-xnold[n][d]-xnew[n][d])/gmx::square(dt)
                 - f[n][d]*md->invmass[n];
         }
         clear_rvec(acc_dir[n]);
@@ -969,8 +964,8 @@ static void init_adir(FILE *log, gmx_shellfc_t *shfc,
 
     /* Project the acceleration on the old bond directions */
     constrain(log, FALSE, FALSE, constr, idef, ir, cr, step, 0, 1.0, md,
-              x_old, xnew-start, acc_dir, bMolPBC, box,
-              lambda[efptBONDED], &(dvdlambda[efptBONDED]),
+              x_old, xnew, acc_dir, bMolPBC, box,
+              (*lambda)[efptBONDED], &(dvdlambda[efptBONDED]),
               NULL, NULL, nrnb, econqDeriv_FlexCon);
 }
 
@@ -980,7 +975,7 @@ void relax_shell_flexcon(FILE *fplog, t_commrec *cr, gmx_bool bVerbose,
                          gmx_localtop_t *top,
                          gmx_constr_t constr,
                          gmx_enerdata_t *enerd, t_fcdata *fcd,
-                         t_state *state, rvec f[],
+                         t_state *state, PaddedRVecVector *f,
                          tensor force_vir,
                          t_mdatoms *md,
                          t_nrnb *nrnb, gmx_wallcycle_t wcycle,
@@ -990,20 +985,19 @@ void relax_shell_flexcon(FILE *fplog, t_commrec *cr, gmx_bool bVerbose,
                          t_forcerec *fr,
                          gmx_bool bBornRadii,
                          double t, rvec mu_tot,
-                         gmx_vsite_t *vsite,
-                         FILE *fp_field)
+                         gmx_vsite_t *vsite)
 {
     int        nshell;
     t_shell   *shell;
     t_idef    *idef;
-    rvec      *pos[2], *force[2], *acc_dir = NULL, *x_old = NULL;
+    rvec      *acc_dir = NULL, *x_old = NULL;
     real       Epot[2], df[2];
     real       sf_dir, invdt;
     real       ftol, dum = 0;
     char       sbuf[22];
     gmx_bool   bCont, bInit, bConverged;
     int        nat, dd_ac0, dd_ac1 = 0, i;
-    int        start = 0, homenr = md->homenr, end = start+homenr, cg0, cg1;
+    int        homenr = md->homenr, end = homenr, cg0, cg1;
     int        nflexcon, number_steps, d, Min = 0, count = 0;
 #define  Try (1-Min)             /* At start Try = 1 */
 
@@ -1031,20 +1025,19 @@ void relax_shell_flexcon(FILE *fplog, t_commrec *cr, gmx_bool bVerbose,
         nat = state->natoms;
     }
 
-    if (nat > shfc->x_nalloc)
+    for (i = 0; (i < 2); i++)
     {
-        /* Allocate local arrays */
-        shfc->x_nalloc = over_alloc_dd(nat);
-        for (i = 0; (i < 2); i++)
-        {
-            srenew(shfc->x[i], shfc->x_nalloc);
-            srenew(shfc->f[i], shfc->x_nalloc);
-        }
+        shfc->x[i].resize(nat + 1);
+        shfc->f[i].resize(nat + 1);
     }
+
+    /* Create pointer that we can swap */
+    PaddedRVecVector *pos[2];
+    PaddedRVecVector *force[2];
     for (i = 0; (i < 2); i++)
     {
-        pos[i]   = shfc->x[i];
-        force[i] = shfc->f[i];
+        pos[i]   = &shfc->x[i];
+        force[i] = &shfc->f[i];
     }
 
     if (bDoNS && inputrec->ePBC != epbcNONE && !DOMAINDECOMP(cr))
@@ -1055,26 +1048,26 @@ void relax_shell_flexcon(FILE *fplog, t_commrec *cr, gmx_bool bVerbose,
          */
         if (inputrec->cutoff_scheme == ecutsVERLET)
         {
-            put_atoms_in_box_omp(fr->ePBC, state->box, md->homenr, state->x);
+            put_atoms_in_box_omp(fr->ePBC, state->box, md->homenr, as_rvec_array(state->x.data()));
         }
         else
         {
             cg0 = 0;
             cg1 = top->cgs.nr;
             put_charge_groups_in_box(fplog, cg0, cg1, fr->ePBC, state->box,
-                                     &(top->cgs), state->x, fr->cg_cm);
+                                     &(top->cgs), as_rvec_array(state->x.data()), fr->cg_cm);
         }
 
         if (graph)
         {
-            mk_mshift(fplog, graph, fr->ePBC, state->box, state->x);
+            mk_mshift(fplog, graph, fr->ePBC, state->box, as_rvec_array(state->x.data()));
         }
     }
 
     /* After this all coordinate arrays will contain whole charge groups */
     if (graph)
     {
-        shift_self(graph, state->box, state->x);
+        shift_self(graph, state->box, as_rvec_array(state->x.data()));
     }
 
     if (nflexcon)
@@ -1092,7 +1085,7 @@ void relax_shell_flexcon(FILE *fplog, t_commrec *cr, gmx_bool bVerbose,
             for (d = 0; d < DIM; d++)
             {
                 shfc->x_old[i][d] =
-                    state->x[start+i][d] - state->v[start+i][d]*inputrec->delta_t;
+                    state->x[i][d] - state->v[i][d]*inputrec->delta_t;
             }
         }
     }
@@ -1100,46 +1093,46 @@ void relax_shell_flexcon(FILE *fplog, t_commrec *cr, gmx_bool bVerbose,
     /* Do a prediction of the shell positions */
     if (shfc->bPredict && !bCont)
     {
-        predict_shells(fplog, state->x, state->v, inputrec->delta_t, nshell, shell,
+        predict_shells(fplog, as_rvec_array(state->x.data()), as_rvec_array(state->v.data()), inputrec->delta_t, nshell, shell,
                        md->massT, NULL, bInit);
     }
 
     /* do_force expected the charge groups to be in the box */
     if (graph)
     {
-        unshift_self(graph, state->box, state->x);
+        unshift_self(graph, state->box, as_rvec_array(state->x.data()));
     }
 
     /* Calculate the forces first time around */
     if (gmx_debug_at)
     {
-        pr_rvecs(debug, 0, "x b4 do_force", state->x + start, homenr);
+        pr_rvecs(debug, 0, "x b4 do_force", as_rvec_array(state->x.data()), homenr);
     }
     do_force(fplog, cr, inputrec, mdstep, nrnb, wcycle, top, groups,
-             state->box, state->x, &state->hist,
+             state->box, &state->x, &state->hist,
              force[Min], force_vir, md, enerd, fcd,
-             state->lambda, graph,
-             fr, vsite, mu_tot, t, fp_field, NULL, bBornRadii,
+             &state->lambda, graph,
+             fr, vsite, mu_tot, t, NULL, bBornRadii,
              (bDoNS ? GMX_FORCE_NS : 0) | force_flags);
 
     sf_dir = 0;
     if (nflexcon)
     {
         init_adir(fplog, shfc,
-                  constr, idef, inputrec, cr, dd_ac1, mdstep, md, start, end,
-                  shfc->x_old-start, state->x, state->x, force[Min],
-                  shfc->acc_dir-start,
-                  fr->bMolPBC, state->box, state->lambda, &dum, nrnb);
+                  constr, idef, inputrec, cr, dd_ac1, mdstep, md, end,
+                  shfc->x_old, as_rvec_array(state->x.data()), as_rvec_array(state->x.data()), as_rvec_array(force[Min]->data()),
+                  shfc->acc_dir,
+                  fr->bMolPBC, state->box, &state->lambda, &dum, nrnb);
 
-        for (i = start; i < end; i++)
+        for (i = 0; i < end; i++)
         {
-            sf_dir += md->massT[i]*norm2(shfc->acc_dir[i-start]);
+            sf_dir += md->massT[i]*norm2(shfc->acc_dir[i]);
         }
     }
 
     Epot[Min] = enerd->term[F_EPOT];
 
-    df[Min] = rms_force(cr, shfc->f[Min], nshell, shell, nflexcon, &sf_dir, &Epot[Min]);
+    df[Min] = rms_force(cr, &shfc->f[Min], nshell, shell, nflexcon, &sf_dir, &Epot[Min]);
     df[Try] = 0;
     if (debug)
     {
@@ -1148,7 +1141,7 @@ void relax_shell_flexcon(FILE *fplog, t_commrec *cr, gmx_bool bVerbose,
 
     if (gmx_debug_at)
     {
-        pr_rvecs(debug, 0, "force0", force[Min], md->nr);
+        pr_rvecs(debug, 0, "force0", as_rvec_array(force[Min]->data()), md->nr);
     }
 
     if (nshell+nflexcon > 0)
@@ -1157,8 +1150,8 @@ void relax_shell_flexcon(FILE *fplog, t_commrec *cr, gmx_bool bVerbose,
          * shell positions are updated, therefore the other particles must
          * be set here.
          */
-        memcpy(pos[Min], state->x, nat*sizeof(state->x[0]));
-        memcpy(pos[Try], state->x, nat*sizeof(state->x[0]));
+        *pos[Min] = state->x;
+        *pos[Try] = state->x;
     }
 
     if (bVerbose && MASTER(cr))
@@ -1186,7 +1179,8 @@ void relax_shell_flexcon(FILE *fplog, t_commrec *cr, gmx_bool bVerbose,
     {
         if (vsite)
         {
-            construct_vsites(vsite, pos[Min], inputrec->delta_t, state->v,
+            construct_vsites(vsite, as_rvec_array(pos[Min]->data()),
+                             inputrec->delta_t, as_rvec_array(state->v.data()),
                              idef->iparams, idef->il,
                              fr->ePBC, fr->bMolPBC, cr, state->box);
         }
@@ -1194,12 +1188,11 @@ void relax_shell_flexcon(FILE *fplog, t_commrec *cr, gmx_bool bVerbose,
         if (nflexcon)
         {
             init_adir(fplog, shfc,
-                      constr, idef, inputrec, cr, dd_ac1, mdstep, md, start, end,
-                      x_old-start, state->x, pos[Min], force[Min], acc_dir-start,
-                      fr->bMolPBC, state->box, state->lambda, &dum, nrnb);
+                      constr, idef, inputrec, cr, dd_ac1, mdstep, md, end,
+                      x_old, as_rvec_array(state->x.data()), as_rvec_array(pos[Min]->data()), as_rvec_array(force[Min]->data()), acc_dir,
+                      fr->bMolPBC, state->box, &state->lambda, &dum, nrnb);
 
-            directional_sd(pos[Min], pos[Try], acc_dir-start, start, end,
-                           fr->fc_stepsize);
+            directional_sd(pos[Min], pos[Try], acc_dir, end, fr->fc_stepsize);
         }
 
         /* New positions, Steepest descent */
@@ -1208,38 +1201,38 @@ void relax_shell_flexcon(FILE *fplog, t_commrec *cr, gmx_bool bVerbose,
         /* do_force expected the charge groups to be in the box */
         if (graph)
         {
-            unshift_self(graph, state->box, pos[Try]);
+            unshift_self(graph, state->box, as_rvec_array(pos[Try]->data()));
         }
 
         if (gmx_debug_at)
         {
-            pr_rvecs(debug, 0, "RELAX: pos[Min]  ", pos[Min] + start, homenr);
-            pr_rvecs(debug, 0, "RELAX: pos[Try]  ", pos[Try] + start, homenr);
+            pr_rvecs(debug, 0, "RELAX: pos[Min]  ", as_rvec_array(pos[Min]->data()), homenr);
+            pr_rvecs(debug, 0, "RELAX: pos[Try]  ", as_rvec_array(pos[Try]->data()), homenr);
         }
         /* Try the new positions */
         do_force(fplog, cr, inputrec, 1, nrnb, wcycle,
                  top, groups, state->box, pos[Try], &state->hist,
                  force[Try], force_vir,
-                 md, enerd, fcd, state->lambda, graph,
-                 fr, vsite, mu_tot, t, fp_field, NULL, bBornRadii,
+                 md, enerd, fcd, &state->lambda, graph,
+                 fr, vsite, mu_tot, t, NULL, bBornRadii,
                  force_flags);
 
         if (gmx_debug_at)
         {
-            pr_rvecs(debug, 0, "RELAX: force[Min]", force[Min] + start, homenr);
-            pr_rvecs(debug, 0, "RELAX: force[Try]", force[Try] + start, homenr);
+            pr_rvecs(debug, 0, "RELAX: force[Min]", as_rvec_array(force[Min]->data()), homenr);
+            pr_rvecs(debug, 0, "RELAX: force[Try]", as_rvec_array(force[Try]->data()), homenr);
         }
         sf_dir = 0;
         if (nflexcon)
         {
             init_adir(fplog, shfc,
-                      constr, idef, inputrec, cr, dd_ac1, mdstep, md, start, end,
-                      x_old-start, state->x, pos[Try], force[Try], acc_dir-start,
-                      fr->bMolPBC, state->box, state->lambda, &dum, nrnb);
+                      constr, idef, inputrec, cr, dd_ac1, mdstep, md, end,
+                      x_old, as_rvec_array(state->x.data()), as_rvec_array(pos[Try]->data()), as_rvec_array(force[Try]->data()), acc_dir,
+                      fr->bMolPBC, state->box, &state->lambda, &dum, nrnb);
 
-            for (i = start; i < end; i++)
+            for (i = 0; i < end; i++)
             {
-                sf_dir += md->massT[i]*norm2(acc_dir[i-start]);
+                sf_dir += md->massT[i]*norm2(acc_dir[i]);
             }
         }
 
@@ -1256,12 +1249,12 @@ void relax_shell_flexcon(FILE *fplog, t_commrec *cr, gmx_bool bVerbose,
         {
             if (gmx_debug_at)
             {
-                pr_rvecs(debug, 0, "F na do_force", force[Try] + start, homenr);
+                pr_rvecs(debug, 0, "F na do_force", as_rvec_array(force[Try]->data()), homenr);
             }
             if (gmx_debug_at)
             {
                 fprintf(debug, "SHELL ITER %d\n", count);
-                dump_shells(debug, pos[Try], force[Try], ftol, nshell, shell);
+                dump_shells(debug, *pos[Try], *force[Try], ftol, nshell, shell);
             }
         }
 
@@ -1282,7 +1275,7 @@ void relax_shell_flexcon(FILE *fplog, t_commrec *cr, gmx_bool bVerbose,
             {
                 /* Correct the velocities for the flexible constraints */
                 invdt = 1/inputrec->delta_t;
-                for (i = start; i < end; i++)
+                for (i = 0; i < end; i++)
                 {
                     for (d = 0; d < DIM; d++)
                     {
@@ -1317,8 +1310,8 @@ void relax_shell_flexcon(FILE *fplog, t_commrec *cr, gmx_bool bVerbose,
     }
 
     /* Copy back the coordinates and the forces */
-    memcpy(state->x, pos[Min], nat*sizeof(state->x[0]));
-    memcpy(f, force[Min], nat*sizeof(f[0]));
+    state->x = *pos[Min];
+    *f       = *force[Min];
 }
 
 void done_shellfc(FILE *fplog, gmx_shellfc_t *shfc, gmx_int64_t numSteps)
index 11581d0f9b2ec72ccf81aef30eefd003af17390d..f02f5127df8df44fb2c622bfdd10a44046d038f7 100644 (file)
@@ -40,6 +40,7 @@
 #include <cstdio>
 
 #include "gromacs/mdlib/vsite.h"
+#include "gromacs/mdtypes/state.h"
 #include "gromacs/timing/wallcycle.h"
 
 struct gmx_constr;
@@ -71,7 +72,7 @@ void relax_shell_flexcon(FILE *log, t_commrec *cr, gmx_bool bVerbose,
                          gmx_localtop_t *top,
                          gmx_constr *constr,
                          gmx_enerdata_t *enerd, t_fcdata *fcd,
-                         t_state *state, rvec f[],
+                         t_state *state, PaddedRVecVector *f,
                          tensor force_vir,
                          t_mdatoms *md,
                          t_nrnb *nrnb, gmx_wallcycle_t wcycle,
@@ -81,8 +82,7 @@ void relax_shell_flexcon(FILE *log, t_commrec *cr, gmx_bool bVerbose,
                          t_forcerec *fr,
                          gmx_bool bBornRadii,
                          double t, rvec mu_tot,
-                         gmx_vsite_t *vsite,
-                         FILE *fp_field);
+                         gmx_vsite_t *vsite);
 
 /* Print some final output */
 void done_shellfc(FILE *fplog, gmx_shellfc_t *shellfc, gmx_int64_t numSteps);
index 5fd64cb318699b095a0d60214ea0a15198d71725..7353e0d7d5b4a537cf19de972df40743f43709ef 100644 (file)
@@ -45,6 +45,8 @@
 #include <stdio.h>
 #include <string.h>
 
+#include <cstdint>
+
 #include <array>
 
 #include "gromacs/domdec/domdec.h"
@@ -203,89 +205,18 @@ void print_start(FILE *fplog, t_commrec *cr,
                         walltime_accounting_get_start_time_stamp(walltime_accounting));
 }
 
-static void sum_forces(int start, int end, rvec f[], rvec flr[])
+static void sum_forces(rvec f[], const PaddedRVecVector *forceToAdd)
 {
-    int i;
+    /* TODO: remove this - 1 when padding is properly implemented */
+    int         end  = forceToAdd->size() - 1;
+    const rvec *fAdd = as_rvec_array(forceToAdd->data());
 
-    if (gmx_debug_at)
-    {
-        pr_rvecs(debug, 0, "fsr", f+start, end-start);
-        pr_rvecs(debug, 0, "flr", flr+start, end-start);
-    }
     // cppcheck-suppress unreadVariable
     int gmx_unused nt = gmx_omp_nthreads_get(emntDefault);
 #pragma omp parallel for num_threads(nt) schedule(static)
-    for (i = start; i < end; i++)
+    for (int i = 0; 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.
- * Ex[] contains the parameters for
- * the spatial dependent part of the field.
- * 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-consistent electric field into PME.
- */
-static void calc_f_el(FILE *fp, int  start, int homenr,
-                      real charge[], 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] = std::cos(Et[m].a[0]*(t-t0))*std::exp(-gmx::square(t-t0)/(2.0*gmx::square(Et[m].a[2])));
-            }
-            else
-            {
-                Ext[m] = std::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);
+        rvec_inc(f[i], fAdd[i]);
     }
 }
 
@@ -370,7 +301,7 @@ static void pme_receive_force_ener(t_commrec      *cr,
     wallcycle_start(wcycle, ewcPP_PMEWAITRECVF);
     dvdl_q  = 0;
     dvdl_lj = 0;
-    gmx_pme_receive_f(cr, fr->f_novirsum, fr->vir_el_recip, &e_q,
+    gmx_pme_receive_f(cr, as_rvec_array(fr->f_novirsum->data()), fr->vir_el_recip, &e_q,
                       fr->vir_lj_recip, &e_lj, &dvdl_q, &dvdl_lj,
                       &cycles_seppme);
     enerd->term[F_COUL_RECIP] += e_q;
@@ -386,24 +317,34 @@ static void pme_receive_force_ener(t_commrec      *cr,
 }
 
 static void print_large_forces(FILE *fp, t_mdatoms *md, t_commrec *cr,
-                               gmx_int64_t step, real pforce, rvec *x, rvec *f)
+                               gmx_int64_t step, real forceTolerance,
+                               const rvec *x, const rvec *f)
 {
-    int  i;
-    real pf2, fn2;
-    char buf[STEPSTRSIZE];
-
-    pf2 = gmx::square(pforce);
-    for (i = 0; i < md->homenr; i++)
+    real           force2Tolerance = gmx::square(forceTolerance);
+    std::uintmax_t numNonFinite    = 0;
+    for (int i = 0; i < md->homenr; i++)
     {
-        fn2 = norm2(f[i]);
-        /* We also catch NAN, if the compiler does not optimize this away. */
-        if (fn2 >= pf2 || fn2 != fn2)
+        real force2    = norm2(f[i]);
+        bool nonFinite = !std::isfinite(force2);
+        if (force2 >= force2Tolerance || nonFinite)
+        {
+            fprintf(fp, "step %" GMX_PRId64 " atom %6d  x %8.3f %8.3f %8.3f  force %12.5e\n",
+                    step,
+                    ddglatnr(cr->dd, i), x[i][XX], x[i][YY], x[i][ZZ], std::sqrt(force2));
+        }
+        if (nonFinite)
         {
-            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], std::sqrt(fn2));
+            numNonFinite++;
         }
     }
+    if (numNonFinite > 0)
+    {
+        /* Note that with MPI this fatal call on one rank might interrupt
+         * the printing on other ranks. But we can only avoid that with
+         * an expensive MPI barrier that we would need at each step.
+         */
+        gmx_fatal(FARGS, "At step %" GMX_PRId64 " detected non-finite forces on %ju atoms", step, numNonFinite);
+    }
 }
 
 static void post_process_forces(t_commrec *cr,
@@ -427,7 +368,7 @@ static void post_process_forces(t_commrec *cr,
              * if the constructing atoms aren't local.
              */
             wallcycle_start(wcycle, ewcVSITESPREAD);
-            spread_vsite_f(vsite, x, fr->f_novirsum, NULL,
+            spread_vsite_f(vsite, x, as_rvec_array(fr->f_novirsum->data()), NULL,
                            (flags & GMX_FORCE_VIRIAL), fr->vir_el_recip,
                            nrnb,
                            &top->idef, fr->ePBC, fr->bMolPBC, graph, box, cr);
@@ -436,15 +377,8 @@ static void post_process_forces(t_commrec *cr,
         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(0, mdatoms->homenr,
-                           f, fr->f_novirsum);
-            }
+            sum_forces(f, fr->f_novirsum);
+
             if (EEL_FULL(fr->eeltype))
             {
                 /* Add the mesh contribution to the virial */
@@ -786,19 +720,18 @@ void do_force_cutsVERLET(FILE *fplog, t_commrec *cr,
                          gmx_localtop_t *top,
                          gmx_groups_t gmx_unused *groups,
                          matrix box, rvec x[], history_t *hist,
-                         rvec f[],
+                         PaddedRVecVector *force,
                          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,
+                         double t, gmx_edsam_t ed,
                          gmx_bool bBornRadii,
                          int flags)
 {
     int                 cg1, i, j;
-    int                 start, homenr;
     double              mu[2*DIM];
     gmx_bool            bStateChanged, bNS, bFillGrid, bCalcCGCM;
     gmx_bool            bDoForces, bUseGPU, bUseOrEmulGPU;
@@ -815,8 +748,8 @@ void do_force_cutsVERLET(FILE *fplog, t_commrec *cr,
     cycles_wait_gpu = 0;
     nbv             = fr->nbv;
 
-    start  = 0;
-    homenr = mdatoms->homenr;
+    const int start  = 0;
+    const int homenr = mdatoms->homenr;
 
     clear_mat(vir_force);
 
@@ -892,8 +825,6 @@ void do_force_cutsVERLET(FILE *fplog, t_commrec *cr,
          * we do not need to worry about shifting.
          */
 
-        int pme_flags = 0;
-
         wallcycle_start(wcycle, ewcPP_PMESENDX);
 
         bBS = (inputrec->nwall == 2);
@@ -903,20 +834,10 @@ void do_force_cutsVERLET(FILE *fplog, t_commrec *cr,
             svmul(inputrec->wall_ewald_zfac, boxs[ZZ], boxs[ZZ]);
         }
 
-        if (EEL_PME(fr->eeltype))
-        {
-            pme_flags |= GMX_PME_DO_COULOMB;
-        }
-
-        if (EVDW_PME(fr->vdwtype))
-        {
-            pme_flags |= GMX_PME_DO_LJ;
-        }
-
         gmx_pme_send_coordinates(cr, bBS ? boxs : box, x,
-                                 mdatoms->nChargePerturbed, mdatoms->nTypePerturbed, lambda[efptCOUL], lambda[efptVDW],
+                                 lambda[efptCOUL], lambda[efptVDW],
                                  (flags & (GMX_FORCE_VIRIAL | GMX_FORCE_ENERGY)),
-                                 pme_flags, step);
+                                 step);
 
         wallcycle_stop(wcycle, ewcPP_PMESENDX);
     }
@@ -1171,6 +1092,9 @@ void do_force_cutsVERLET(FILE *fplog, t_commrec *cr,
         wallcycle_stop(wcycle, ewcROT);
     }
 
+    /* Temporary solution until all routines take PaddedRVecVector */
+    rvec *f = as_rvec_array(force->data());
+
     /* Start the force cycle counter.
      * This counter is stopped after do_force_lowlevel.
      * No parallel communication should occur while this counter is running,
@@ -1185,7 +1109,7 @@ void do_force_cutsVERLET(FILE *fplog, t_commrec *cr,
         {
             if (flags & GMX_FORCE_VIRIAL)
             {
-                fr->f_novirsum = fr->f_novirsum_alloc;
+                fr->f_novirsum = fr->forceBufferNoVirialSummation;
             }
             else
             {
@@ -1193,7 +1117,7 @@ void do_force_cutsVERLET(FILE *fplog, t_commrec *cr,
                  * a separate array for forces that do not contribute
                  * to the pressure.
                  */
-                fr->f_novirsum = f;
+                fr->f_novirsum = force;
             }
         }
 
@@ -1201,14 +1125,9 @@ void do_force_cutsVERLET(FILE *fplog, t_commrec *cr,
         {
             if (flags & GMX_FORCE_VIRIAL)
             {
-                if (fr->bDomDec)
-                {
-                    clear_rvecs_omp(fr->f_novirsum_n, fr->f_novirsum);
-                }
-                else
-                {
-                    clear_rvecs_omp(homenr, fr->f_novirsum+start);
-                }
+                /* TODO: remove this - 1 when padding is properly implemented */
+                clear_rvecs_omp(fr->f_novirsum->size() - 1,
+                                as_rvec_array(fr->f_novirsum->data()));
             }
         }
         /* Clear the short- and long-range forces */
@@ -1464,12 +1383,10 @@ void do_force_cutsVERLET(FILE *fplog, t_commrec *cr,
 
     if (bDoForces)
     {
-        if (inputrecElecField(inputrec))
+        /* Compute forces due to electric field */
+        if (fr->efield != nullptr)
         {
-            /* Compute forces due to electric field */
-            calc_f_el(MASTER(cr) ? field : NULL,
-                      start, homenr, mdatoms->chargeA, fr->f_novirsum,
-                      inputrec->ex, inputrec->et, t);
+            fr->efield->calculateForces(cr, mdatoms, fr->f_novirsum, t);
         }
 
         /* If we have NoVirSum forces, but we do not calculate the virial,
@@ -1545,25 +1462,24 @@ void do_force_cutsGROUP(FILE *fplog, t_commrec *cr,
                         gmx_localtop_t *top,
                         gmx_groups_t *groups,
                         matrix box, rvec x[], history_t *hist,
-                        rvec f[],
+                        PaddedRVecVector *force,
                         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,
+                        double t, gmx_edsam_t ed,
                         gmx_bool bBornRadii,
                         int flags)
 {
     int        cg0, cg1, i, j;
-    int        start, homenr;
     double     mu[2*DIM];
     gmx_bool   bStateChanged, bNS, bFillGrid, bCalcCGCM;
     gmx_bool   bDoForces;
     float      cycles_pme, cycles_force;
 
-    start  = 0;
-    homenr = mdatoms->homenr;
+    const int  start  = 0;
+    const int  homenr = mdatoms->homenr;
 
     clear_mat(vir_force);
 
@@ -1648,8 +1564,6 @@ void do_force_cutsGROUP(FILE *fplog, t_commrec *cr,
          * we do not need to worry about shifting.
          */
 
-        int pme_flags = 0;
-
         wallcycle_start(wcycle, ewcPP_PMESENDX);
 
         bBS = (inputrec->nwall == 2);
@@ -1659,20 +1573,10 @@ void do_force_cutsGROUP(FILE *fplog, t_commrec *cr,
             svmul(inputrec->wall_ewald_zfac, boxs[ZZ], boxs[ZZ]);
         }
 
-        if (EEL_PME(fr->eeltype))
-        {
-            pme_flags |= GMX_PME_DO_COULOMB;
-        }
-
-        if (EVDW_PME(fr->vdwtype))
-        {
-            pme_flags |= GMX_PME_DO_LJ;
-        }
-
         gmx_pme_send_coordinates(cr, bBS ? boxs : box, x,
-                                 mdatoms->nChargePerturbed, mdatoms->nTypePerturbed, lambda[efptCOUL], lambda[efptVDW],
+                                 lambda[efptCOUL], lambda[efptVDW],
                                  (flags & (GMX_FORCE_VIRIAL | GMX_FORCE_ENERGY)),
-                                 pme_flags, step);
+                                 step);
 
         wallcycle_stop(wcycle, ewcPP_PMESENDX);
     }
@@ -1760,6 +1664,9 @@ void do_force_cutsGROUP(FILE *fplog, t_commrec *cr,
         wallcycle_stop(wcycle, ewcROT);
     }
 
+    /* Temporary solution until all routines take PaddedRVecVector */
+    rvec *f = as_rvec_array(force->data());
+
     /* Start the force cycle counter.
      * This counter is stopped after do_force_lowlevel.
      * No parallel communication should occur while this counter is running,
@@ -1775,15 +1682,10 @@ void do_force_cutsGROUP(FILE *fplog, t_commrec *cr,
         {
             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);
-                }
+                fr->f_novirsum = fr->forceBufferNoVirialSummation;
+                /* TODO: remove this - 1 when padding is properly implemented */
+                clear_rvecs(fr->f_novirsum->size() - 1,
+                            as_rvec_array(fr->f_novirsum->data()));
             }
             else
             {
@@ -1791,7 +1693,7 @@ void do_force_cutsGROUP(FILE *fplog, t_commrec *cr,
                  * a separate array for forces that do not contribute
                  * to the pressure.
                  */
-                fr->f_novirsum = f;
+                fr->f_novirsum = force;
             }
         }
 
@@ -1839,12 +1741,10 @@ void do_force_cutsGROUP(FILE *fplog, t_commrec *cr,
 
     if (bDoForces)
     {
-        if (inputrecElecField(inputrec))
+        /* Compute forces due to electric field */
+        if (fr->efield != nullptr)
         {
-            /* Compute forces due to electric field */
-            calc_f_el(MASTER(cr) ? field : NULL,
-                      start, homenr, mdatoms->chargeA, fr->f_novirsum,
-                      inputrec->ex, inputrec->et, t);
+            fr->efield->calculateForces(cr, mdatoms, fr->f_novirsum, t);
         }
 
         /* Communicate the forces */
@@ -1862,7 +1762,7 @@ void do_force_cutsGROUP(FILE *fplog, t_commrec *cr,
             if (EEL_FULL(fr->eeltype) && cr->dd->n_intercg_excl &&
                 (flags & GMX_FORCE_VIRIAL))
             {
-                dd_move_f(cr->dd, fr->f_novirsum, NULL);
+                dd_move_f(cr->dd, as_rvec_array(fr->f_novirsum->data()), NULL);
             }
             wallcycle_stop(wcycle, ewcMOVEF);
         }
@@ -1937,15 +1837,15 @@ void do_force(FILE *fplog, t_commrec *cr,
               gmx_int64_t step, t_nrnb *nrnb, gmx_wallcycle_t wcycle,
               gmx_localtop_t *top,
               gmx_groups_t *groups,
-              matrix box, rvec x[], history_t *hist,
-              rvec f[],
+              matrix box, PaddedRVecVector *coordinates, history_t *hist,
+              PaddedRVecVector *force,
               tensor vir_force,
               t_mdatoms *mdatoms,
               gmx_enerdata_t *enerd, t_fcdata *fcd,
-              real *lambda, t_graph *graph,
+              std::vector<real> *lambda, t_graph *graph,
               t_forcerec *fr,
               gmx_vsite_t *vsite, rvec mu_tot,
-              double t, FILE *field, gmx_edsam_t ed,
+              double t, gmx_edsam_t ed,
               gmx_bool bBornRadii,
               int flags)
 {
@@ -1955,6 +1855,11 @@ void do_force(FILE *fplog, t_commrec *cr,
         flags &= ~GMX_FORCE_NONBONDED;
     }
 
+    GMX_ASSERT(coordinates->size() >= static_cast<unsigned int>(fr->natoms_force + 1), "We might need 1 element extra for SIMD");
+    GMX_ASSERT(force->size() >= static_cast<unsigned int>(fr->natoms_force + 1), "We might need 1 element extra for SIMD");
+
+    rvec *x = as_rvec_array(coordinates->data());
+
     switch (inputrec->cutoff_scheme)
     {
         case ecutsVERLET:
@@ -1963,13 +1868,13 @@ void do_force(FILE *fplog, t_commrec *cr,
                                 top,
                                 groups,
                                 box, x, hist,
-                                f, vir_force,
+                                force, vir_force,
                                 mdatoms,
                                 enerd, fcd,
-                                lambda, graph,
+                                lambda->data(), graph,
                                 fr, fr->ic,
                                 vsite, mu_tot,
-                                t, field, ed,
+                                t, ed,
                                 bBornRadii,
                                 flags);
             break;
@@ -1979,12 +1884,12 @@ void do_force(FILE *fplog, t_commrec *cr,
                                top,
                                groups,
                                box, x, hist,
-                               f, vir_force,
+                               force, vir_force,
                                mdatoms,
                                enerd, fcd,
-                               lambda, graph,
+                               lambda->data(), graph,
                                fr, vsite, mu_tot,
-                               t, field, ed,
+                               t, ed,
                                bBornRadii,
                                flags);
             break;
@@ -2031,7 +1936,7 @@ void do_constrain_first(FILE *fplog, gmx_constr_t constr,
     /* constrain the current position */
     constrain(NULL, TRUE, FALSE, constr, &(top->idef),
               ir, cr, step, 0, 1.0, md,
-              state->x, state->x, NULL,
+              as_rvec_array(state->x.data()), as_rvec_array(state->x.data()), NULL,
               fr->bMolPBC, state->box,
               state->lambda[efptBONDED], &dvdl_dum,
               NULL, NULL, nrnb, econqCoord);
@@ -2041,7 +1946,7 @@ void do_constrain_first(FILE *fplog, gmx_constr_t constr,
         /* also may be useful if we need the ekin from the halfstep for velocity verlet */
         constrain(NULL, TRUE, FALSE, constr, &(top->idef),
                   ir, cr, step, 0, 1.0, md,
-                  state->x, state->v, state->v,
+                  as_rvec_array(state->x.data()), as_rvec_array(state->v.data()), as_rvec_array(state->v.data()),
                   fr->bMolPBC, state->box,
                   state->lambda[efptBONDED], &dvdl_dum,
                   NULL, NULL, nrnb, econqVeloc);
@@ -2071,10 +1976,10 @@ void do_constrain_first(FILE *fplog, gmx_constr_t constr,
         dvdl_dum = 0;
         constrain(NULL, TRUE, FALSE, constr, &(top->idef),
                   ir, cr, step, -1, 1.0, md,
-                  state->x, savex, NULL,
+                  as_rvec_array(state->x.data()), savex, NULL,
                   fr->bMolPBC, state->box,
                   state->lambda[efptBONDED], &dvdl_dum,
-                  state->v, NULL, nrnb, econqCoord);
+                  as_rvec_array(state->v.data()), NULL, nrnb, econqCoord);
 
         for (i = start; i < end; i++)
         {
@@ -2559,7 +2464,7 @@ void put_atoms_in_box_omp(int ePBC, const matrix box, int natoms, rvec x[])
 }
 
 // TODO This can be cleaned up a lot, and move back to runner.cpp
-void finish_run(FILE *fplog, t_commrec *cr,
+void finish_run(FILE *fplog, const gmx::MDLogger &mdlog, t_commrec *cr,
                 t_inputrec *inputrec,
                 t_nrnb nrnb[], gmx_wallcycle_t wcycle,
                 gmx_walltime_accounting_t walltime_accounting,
@@ -2636,7 +2541,7 @@ void finish_run(FILE *fplog, t_commrec *cr,
     {
         struct gmx_wallclock_gpu_t* gputimes = use_GPU(nbv) ? nbnxn_gpu_get_timings(nbv->gpu_nbv) : NULL;
 
-        wallcycle_print(fplog, cr->nnodes, cr->npmenodes, nthreads_pp, nthreads_pme,
+        wallcycle_print(fplog, mdlog, cr->nnodes, cr->npmenodes, nthreads_pp, nthreads_pme,
                         elapsed_time_over_all_ranks,
                         wcycle, cycle_sum, gputimes);
 
@@ -2662,60 +2567,51 @@ void finish_run(FILE *fplog, t_commrec *cr,
     }
 }
 
-extern void initialize_lambdas(FILE *fplog, t_inputrec *ir, int *fep_state, real *lambda, double *lam0)
+extern void initialize_lambdas(FILE *fplog, t_inputrec *ir, int *fep_state, std::vector<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;
+    if ((ir->efep == efepNO) && (ir->bSimTemp == FALSE))
+    {
+        return;
+    }
+
     t_lambda *fep = ir->fepvals;
+    *fep_state    = fep->init_fep_state; /* this might overwrite the checkpoint
+                                            if checkpoint is set -- a kludge is in for now
+                                            to prevent this.*/
 
-    if ((ir->efep == efepNO) && (ir->bSimTemp == FALSE))
+    lambda->resize(efptNR);
+
+    for (int i = 0; i < efptNR; i++)
     {
-        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] = 0.0;
+            (*lambda)[i] = fep->init_lambda;
             if (lam0)
             {
-                lam0[i] = 0.0;
+                lam0[i] = (*lambda)[i];
             }
         }
-        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++)
+        else
         {
-            /* 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)
             {
-                lambda[i] = fep->all_lambda[i][*fep_state];
-                if (lam0)
-                {
-                    lam0[i] = lambda[i];
-                }
+                lam0[i] = (*lambda)[i];
             }
         }
-        if (ir->bSimTemp)
+    }
+    if (ir->bSimTemp)
+    {
+        /* need to rescale control temperatures to match current state */
+        for (int i = 0; i < ir->opts.ngtc; i++)
         {
-            /* need to rescale control temperatures to match current state */
-            for (i = 0; i < ir->opts.ngtc; i++)
+            if (ir->opts.ref_t[i] > 0)
             {
-                if (ir->opts.ref_t[i] > 0)
-                {
-                    ir->opts.ref_t[i] = ir->simtempvals->temperatures[*fep_state];
-                }
+                ir->opts.ref_t[i] = ir->simtempvals->temperatures[*fep_state];
             }
         }
     }
@@ -2724,9 +2620,9 @@ extern void initialize_lambdas(FILE *fplog, t_inputrec *ir, int *fep_state, real
     if (fplog != NULL)
     {
         fprintf(fplog, "Initial vector of lambda components:[ ");
-        for (i = 0; i < efptNR; i++)
+        for (int i = 0; i < efptNR; i++)
         {
-            fprintf(fplog, "%10.4f ", lambda[i]);
+            fprintf(fplog, "%10.4f ", (*lambda)[i]);
         }
         fprintf(fplog, "]\n");
     }
@@ -2737,7 +2633,7 @@ extern void initialize_lambdas(FILE *fplog, t_inputrec *ir, int *fep_state, real
 void init_md(FILE *fplog,
              t_commrec *cr, t_inputrec *ir, const gmx_output_env_t *oenv,
              double *t, double *t0,
-             real *lambda, int *fep_state, double *lam0,
+             std::vector<real> *lambda, int *fep_state, double *lam0,
              t_nrnb *nrnb, gmx_mtop_t *mtop,
              gmx_update_t **upd,
              int nfile, const t_filenm fnm[],
@@ -2794,10 +2690,6 @@ void init_md(FILE *fplog,
             please_cite(fplog, "Goga2012");
         }
     }
-    if ((ir->et[XX].n > 0) || (ir->et[YY].n > 0) || (ir->et[ZZ].n > 0))
-    {
-        please_cite(fplog, "Caleman2008a");
-    }
     init_nrnb(nrnb);
 
     if (nfile != -1)
index 930bf2c692f16935a3266c472d8c4171d67283c2..0b969c514e1bf98a1eb75434be1af6b741899d4f 100644 (file)
@@ -53,6 +53,11 @@ struct t_graph;
 struct t_mdatoms;
 struct t_nrnb;
 
+namespace gmx
+{
+class MDLogger;
+}
+
 typedef struct gmx_global_stat *gmx_global_stat_t;
 
 void do_pbc_first(FILE *log, matrix box, t_forcerec *fr,
@@ -117,7 +122,7 @@ void print_start(FILE *fplog, t_commrec *cr,
                  gmx_walltime_accounting_t walltime_accounting,
                  const char *name);
 
-void finish_run(FILE *log, t_commrec *cr,
+void finish_run(FILE *log, const gmx::MDLogger &mdlog, t_commrec *cr,
                 t_inputrec *inputrec,
                 t_nrnb nrnb[], gmx_wallcycle_t wcycle,
                 gmx_walltime_accounting_t walltime_accounting,
@@ -130,7 +135,7 @@ void calc_dispcorr(t_inputrec *ir, t_forcerec *fr,
                    matrix box, real lambda, tensor pres, tensor virial,
                    real *prescorr, real *enercorr, real *dvdlcorr);
 
-void initialize_lambdas(FILE *fplog, t_inputrec *ir, int *fep_state, real *lambda, double *lam0);
+void initialize_lambdas(FILE *fplog, t_inputrec *ir, int *fep_state, std::vector<real> *lambda, double *lam0);
 
 void do_constrain_first(FILE *log, gmx_constr *constr,
                         t_inputrec *inputrec, t_mdatoms *md,
@@ -140,7 +145,7 @@ void do_constrain_first(FILE *log, gmx_constr *constr,
 void init_md(FILE *fplog,
              t_commrec *cr, t_inputrec *ir, const gmx_output_env_t *oenv,
              double *t, double *t0,
-             real *lambda, int *fep_state, double *lam0,
+             std::vector<real> *lambda, int *fep_state, double *lam0,
              t_nrnb *nrnb, gmx_mtop_t *mtop,
              gmx_update_t **upd,
              int nfile, const t_filenm fnm[],
index abd5ee7bb9fd7b098f1541b91201f3cfbe0917d7..794908c98091e2bede8a6d6bd9e9d2b9610a9503 100644 (file)
@@ -78,9 +78,6 @@ class ArrayRef;
  * signals can be sent together with other data). This means that the
  * only meaningful values are positive, negative or zero.
  *
- * Note that xlc on BG/Q requires sig to be of size char (see unit tests
- * of ArrayRef for details).
- *
  * isLocal permits (for example) replica-exchange to require that any
  * checkpointing is synchronized across all simulations, by setting
  * isLocal to false, so that the trigger for action is set only when
index 4fcb49b7194de52b2e0e96d3fae510b653260ef9..84d54af65615e857c40f6ee558c82fb138e4f5ae 100644 (file)
@@ -261,6 +261,7 @@ TEST_P(SettleTest, SatisfiesConstraints)
             startingPositions.data(), updatedPositions_.data(), reciprocalTimeStep,
             useVelocities ? velocities_.data() : nullptr,
             calcVirial, virial, &errorOccured);
+    settle_free(settled);
     EXPECT_FALSE(errorOccured) << testDescription;
 
     // The necessary tolerances for the test to pass were determined
@@ -309,39 +310,15 @@ TEST_P(SettleTest, SatisfiesConstraints)
     }
 }
 
-using ::testing::Bool;
 // Scan the full Cartesian product of numbers of SETTLE interactions
 // (4 and 17 are chosen to test cases that do and do not match
 // hardware SIMD widths), and whether or not we use PBC, velocities or
-// calculate the virial contribution. It would be nicer to generate
-// these combinations with ::testing::Combine, but gcc 4.6 can't cope
-// with the template meta-programming required to generate the tuples.
+// calculate the virial contribution.
 INSTANTIATE_TEST_CASE_P(WithParameters, SettleTest,
-                            ::testing::Values(SettleTestParameters(1,  true,  true,  true),
-                                              SettleTestParameters(4,  true,  true,  true),
-                                              SettleTestParameters(17, true,  true,  true),
-                                              SettleTestParameters(1,  false, true,  true),
-                                              SettleTestParameters(4,  false, true,  true),
-                                              SettleTestParameters(17, false, true,  true),
-                                              SettleTestParameters(1,  true,  false, true),
-                                              SettleTestParameters(4,  true,  false, true),
-                                              SettleTestParameters(17, true,  false, true),
-                                              SettleTestParameters(1,  false, false, true),
-                                              SettleTestParameters(4,  false, false, true),
-                                              SettleTestParameters(17, false, false, true),
-                                              SettleTestParameters(1,  true,  true,  false),
-                                              SettleTestParameters(4,  true,  true,  false),
-                                              SettleTestParameters(17, true,  true,  false),
-                                              SettleTestParameters(1,  false, true,  false),
-                                              SettleTestParameters(4,  false, true,  false),
-                                              SettleTestParameters(17, false, true,  false),
-                                              SettleTestParameters(1,  true,  false, false),
-                                              SettleTestParameters(4,  true,  false, false),
-                                              SettleTestParameters(17, true,  false, false),
-                                              SettleTestParameters(1,  false, false, false),
-                                              SettleTestParameters(4,  false, false, false),
-                                              SettleTestParameters(17, false, false, false)));
-
+                            ::testing::Combine(::testing::Values(1, 4, 7),
+                                                   ::testing::Bool(),
+                                                   ::testing::Bool(),
+                                                   ::testing::Bool()));
 
 } // namespace
 } // namespace
index 78ece843ca9321ea3707a4833b826577dbefeb37..0d7712be6dbee67f3a1eb6fcc7f201bdeb0d3b75 100644 (file)
@@ -74,7 +74,7 @@ static void init_grpstat(gmx_mtop_t *mtop, int ngacc, t_grp_acc gstat[])
     gmx_groups_t           *groups;
     gmx_mtop_atomloop_all_t aloop;
     int                     i, grp;
-    t_atom                 *atom;
+    const t_atom           *atom;
 
     if (ngacc > 0)
     {
index aa1210a59fdc9641dc89ea5424e16311e0162ebb..b35c713802fef64086cca845abd91bc30cfee003 100644 (file)
@@ -126,7 +126,7 @@ namespace gmx
 {
 
 /*! \brief Do test particle insertion.
-    \copydoc integrator_t (FILE *fplog, t_commrec *cr,
+    \copydoc integrator_t (FILE *fplog, t_commrec *cr, const gmx::MDLogger &mdlog,
                            int nfile, const t_filenm fnm[],
                            const gmx_output_env_t *oenv, gmx_bool bVerbose,
                            int nstglobalcomm,
@@ -145,7 +145,7 @@ namespace gmx
                            unsigned long Flags,
                            gmx_walltime_accounting_t walltime_accounting)
  */
-double do_tpi(FILE *fplog, t_commrec *cr,
+double do_tpi(FILE *fplog, t_commrec *cr, const gmx::MDLogger gmx_unused &mdlog,
               int nfile, const t_filenm fnm[],
               const gmx_output_env_t *oenv, gmx_bool bVerbose,
               int gmx_unused nstglobalcomm,
@@ -154,6 +154,7 @@ double do_tpi(FILE *fplog, t_commrec *cr,
               t_inputrec *inputrec,
               gmx_mtop_t *top_global, t_fcdata *fcd,
               t_state *state_global,
+              energyhistory_t gmx_unused *energyHistory,
               t_mdatoms *mdatoms,
               t_nrnb *nrnb, gmx_wallcycle_t wcycle,
               gmx_edsam_t gmx_unused ed,
@@ -165,35 +166,35 @@ double do_tpi(FILE *fplog, t_commrec *cr,
               unsigned long gmx_unused Flags,
               gmx_walltime_accounting_t walltime_accounting)
 {
-    gmx_localtop_t *top;
-    gmx_groups_t   *groups;
-    gmx_enerdata_t *enerd;
-    rvec           *f;
-    real            lambda, t, temp, beta, drmax, epot;
-    double          embU, sum_embU, *sum_UgembU, V, V_all, VembU_all;
-    t_trxstatus    *status;
-    t_trxframe      rerun_fr;
-    gmx_bool        bDispCorr, bCharge, bRFExcl, bNotLastFrame, bStateChanged, bNS;
-    tensor          force_vir, shake_vir, vir, pres;
-    int             cg_tp, a_tp0, a_tp1, ngid, gid_tp, nener, e;
-    rvec           *x_mol;
-    rvec            mu_tot, x_init, dx, x_tp;
-    int             nnodes, frame;
-    gmx_int64_t     frame_step_prev, frame_step;
-    gmx_int64_t     nsteps, stepblocksize = 0, step;
-    gmx_int64_t     seed;
-    int             i;
-    FILE           *fp_tpi = NULL;
-    char           *ptr, *dump_pdb, **leg, str[STRLEN], str2[STRLEN];
-    double          dbl, dump_ener;
-    gmx_bool        bCavity;
-    int             nat_cavity  = 0, d;
-    real           *mass_cavity = NULL, mass_tot;
-    int             nbin;
-    double          invbinw, *bin, refvolshift, logV, bUlogV;
-    real            prescorr, enercorr, dvdlcorr;
-    gmx_bool        bEnergyOutOfBounds;
-    const char     *tpid_leg[2] = {"direct", "reweighted"};
+    gmx_localtop_t  *top;
+    gmx_groups_t    *groups;
+    gmx_enerdata_t  *enerd;
+    PaddedRVecVector f {};
+    real             lambda, t, temp, beta, drmax, epot;
+    double           embU, sum_embU, *sum_UgembU, V, V_all, VembU_all;
+    t_trxstatus     *status;
+    t_trxframe       rerun_fr;
+    gmx_bool         bDispCorr, bCharge, bRFExcl, bNotLastFrame, bStateChanged, bNS;
+    tensor           force_vir, shake_vir, vir, pres;
+    int              cg_tp, a_tp0, a_tp1, ngid, gid_tp, nener, e;
+    rvec            *x_mol;
+    rvec             mu_tot, x_init, dx, x_tp;
+    int              nnodes, frame;
+    gmx_int64_t      frame_step_prev, frame_step;
+    gmx_int64_t      nsteps, stepblocksize = 0, step;
+    gmx_int64_t      seed;
+    int              i;
+    FILE            *fp_tpi = NULL;
+    char            *ptr, *dump_pdb, **leg, str[STRLEN], str2[STRLEN];
+    double           dbl, dump_ener;
+    gmx_bool         bCavity;
+    int              nat_cavity  = 0, d;
+    real            *mass_cavity = NULL, mass_tot;
+    int              nbin;
+    double           invbinw, *bin, refvolshift, logV, bUlogV;
+    real             prescorr, enercorr, dvdlcorr;
+    gmx_bool         bEnergyOutOfBounds;
+    const char      *tpid_leg[2] = {"direct", "reweighted"};
 
     /* Since there is no upper limit to the insertion energies,
      * we need to set an upper limit for the distribution output.
@@ -284,12 +285,12 @@ double do_tpi(FILE *fplog, t_commrec *cr,
         sscanf(dump_pdb, "%20lf", &dump_ener);
     }
 
-    atoms2md(top_global, inputrec, 0, NULL, top_global->natoms, mdatoms);
+    atoms2md(top_global, inputrec, -1, NULL, top_global->natoms, mdatoms);
     update_mdatoms(mdatoms, inputrec->fepvals->init_lambda);
 
     snew(enerd, 1);
     init_enerdata(groups->grps[egcENER].nr, inputrec->fepvals->n_lambda, enerd);
-    snew(f, top_global->natoms);
+    f.resize(top_global->natoms + 1);
 
     /* Print to log file  */
     walltime_accounting_start(walltime_accounting);
@@ -321,7 +322,7 @@ double do_tpi(FILE *fplog, t_commrec *cr,
     }
     bRFExcl = (bCharge && EEL_RF(fr->eeltype));
 
-    calc_cgcm(fplog, cg_tp, cg_tp+1, &(top->cgs), state_global->x, fr->cg_cm);
+    calc_cgcm(fplog, cg_tp, cg_tp+1, &(top->cgs), as_rvec_array(state_global->x.data()), fr->cg_cm);
     if (bCavity)
     {
         if (norm(fr->cg_cm[cg_tp]) > 0.5*inputrec->rlist && fplog)
@@ -629,7 +630,7 @@ double do_tpi(FILE *fplog, t_commrec *cr,
                     copy_rvec(x_mol[i-a_tp0], state_global->x[i]);
                 }
                 /* Rotate the molecule randomly */
-                rotate_conf(a_tp1-a_tp0, state_global->x+a_tp0, NULL,
+                rotate_conf(a_tp1-a_tp0, as_rvec_array(state_global->x.data())+a_tp0, NULL,
                             2*M_PI*dist(rng),
                             2*M_PI*dist(rng),
                             2*M_PI*dist(rng));
@@ -659,10 +660,10 @@ double do_tpi(FILE *fplog, t_commrec *cr,
             cr->nnodes = 1;
             do_force(fplog, cr, inputrec,
                      step, nrnb, wcycle, top, &top_global->groups,
-                     state_global->box, state_global->x, &state_global->hist,
-                     f, force_vir, mdatoms, enerd, fcd,
-                     state_global->lambda,
-                     NULL, fr, NULL, mu_tot, t, NULL, NULL, FALSE,
+                     state_global->box, &state_global->x, &state_global->hist,
+                     &f, force_vir, mdatoms, enerd, fcd,
+                     &state_global->lambda,
+                     NULL, fr, NULL, mu_tot, t, NULL, FALSE,
                      GMX_FORCE_NONBONDED | GMX_FORCE_ENERGY |
                      (bNS ? GMX_FORCE_DYNAMICBOX | GMX_FORCE_NS : 0) |
                      (bStateChanged ? GMX_FORCE_STATECHANGED : 0));
@@ -782,7 +783,7 @@ double do_tpi(FILE *fplog, t_commrec *cr,
             {
                 sprintf(str, "t%g_step%d.pdb", t, (int)step);
                 sprintf(str2, "t: %f step %d ener: %f", t, (int)step, epot);
-                write_sto_conf_mtop(str, str2, top_global, state_global->x, state_global->v,
+                write_sto_conf_mtop(str, str2, top_global, as_rvec_array(state_global->x.data()), as_rvec_array(state_global->v.data()),
                                     inputrec->ePBC, state_global->box);
             }
 
index d210d731c5f4e02c7bb2bc88bc9bbb8e6b5573a1..93025b5bddc7517991ea845890f04f4c484e2485 100644 (file)
 #include "gromacs/utility/smalloc.h"
 
 void
-do_md_trajectory_writing(FILE           *fplog,
-                         t_commrec      *cr,
-                         int             nfile,
-                         const t_filenm  fnm[],
-                         gmx_int64_t     step,
-                         gmx_int64_t     step_rel,
-                         double          t,
-                         t_inputrec     *ir,
-                         t_state        *state,
-                         t_state        *state_global,
-                         gmx_mtop_t     *top_global,
-                         t_forcerec     *fr,
-                         gmx_mdoutf_t    outf,
-                         t_mdebin       *mdebin,
-                         gmx_ekindata_t *ekind,
-                         rvec           *f,
-                         int            *nchkpt,
-                         gmx_bool        bCPT,
-                         gmx_bool        bRerunMD,
-                         gmx_bool        bLastStep,
-                         gmx_bool        bDoConfOut,
-                         gmx_bool        bSumEkinhOld
+do_md_trajectory_writing(FILE             *fplog,
+                         t_commrec        *cr,
+                         int               nfile,
+                         const t_filenm    fnm[],
+                         gmx_int64_t       step,
+                         gmx_int64_t       step_rel,
+                         double            t,
+                         t_inputrec       *ir,
+                         t_state          *state,
+                         t_state          *state_global,
+                         energyhistory_t  *energyHistory,
+                         gmx_mtop_t       *top_global,
+                         t_forcerec       *fr,
+                         gmx_mdoutf_t      outf,
+                         t_mdebin         *mdebin,
+                         gmx_ekindata_t   *ekind,
+                         PaddedRVecVector *f,
+                         int              *nchkpt,
+                         gmx_bool          bCPT,
+                         gmx_bool          bRerunMD,
+                         gmx_bool          bLastStep,
+                         gmx_bool          bDoConfOut,
+                         gmx_bool          bSumEkinhOld
                          )
 {
     int   mdof_flags;
@@ -139,11 +140,11 @@ do_md_trajectory_writing(FILE           *fplog,
                     update_ekinstate(&state_global->ekinstate, ekind);
                     state_global->ekinstate.bUpToDate = TRUE;
                 }
-                update_energyhistory(state_global->enerhist, mdebin);
+                update_energyhistory(energyHistory, mdebin);
             }
         }
         mdoutf_write_to_trajectory_files(fplog, cr, outf, mdof_flags, top_global,
-                                         step, t, state, state_global, f);
+                                         step, t, state, state_global, energyHistory, f);
         if (bCPT)
         {
             (*nchkpt)++;
@@ -152,7 +153,7 @@ do_md_trajectory_writing(FILE           *fplog,
             bDoConfOut && MASTER(cr) &&
             !bRerunMD)
         {
-            if (fr->bMolPBC && state->x == state_global->x)
+            if (fr->bMolPBC && state == state_global)
             {
                 /* This (single-rank) run needs to allocate a
                    temporary array of size natoms so that any
@@ -162,13 +163,13 @@ do_md_trajectory_writing(FILE           *fplog,
                    identical, and makes .edr restarts binary
                    identical. */
                 snew(x_for_confout, state_global->natoms);
-                copy_rvecn(state_global->x, x_for_confout, 0, state_global->natoms);
+                copy_rvecn(as_rvec_array(state_global->x.data()), x_for_confout, 0, state_global->natoms);
             }
             else
             {
                 /* With DD, or no bMolPBC, it doesn't matter if
-                   we change state_global->x */
-                x_for_confout = state_global->x;
+                   we change as_rvec_array(state_global->x.data()) */
+                x_for_confout = as_rvec_array(state_global->x.data());
             }
 
             /* x and v have been collected in mdoutf_write_to_trajectory_files,
@@ -183,9 +184,9 @@ do_md_trajectory_writing(FILE           *fplog,
             }
             write_sto_conf_mtop(ftp2fn(efSTO, nfile, fnm),
                                 *top_global->name, top_global,
-                                x_for_confout, state_global->v,
+                                x_for_confout, as_rvec_array(state_global->v.data()),
                                 ir->ePBC, state->box);
-            if (fr->bMolPBC && state->x == state_global->x)
+            if (fr->bMolPBC && state == state_global)
             {
                 sfree(x_for_confout);
             }
index f9edb57e83020c896e52518f9c77a154eafa8fdb..c4ee912a59aac42327226d8077d436ec06a32f5a 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -67,12 +67,13 @@ do_md_trajectory_writing(FILE                     *fplog,
                          t_inputrec               *ir,
                          t_state                  *state,
                          t_state                  *state_global,
+                         energyhistory_t          *energyHistory,
                          struct gmx_mtop_t        *top_global,
                          t_forcerec               *fr,
                          gmx_mdoutf_t              outf,
                          t_mdebin                 *mdebin,
                          struct gmx_ekindata_t    *ekind,
-                         rvec                     *f,
+                         PaddedRVecVector         *f,
                          int                      *nchkpt,
                          gmx_bool                  bCPT,
                          gmx_bool                  bRerunMD,
index cc01f266c007e30ea5691bdc99942026f6c9950c..c7c9556ddff69542b23cb4394aaad2d51f02c1ba 100644 (file)
@@ -102,177 +102,403 @@ typedef struct {
 
 struct gmx_update_t
 {
-    gmx_stochd_t *sd;
+    gmx_stochd_t     *sd;
     /* xprime for constraint algorithms */
-    rvec         *xp;
-    int           xp_nalloc;
+    PaddedRVecVector  xp;
 
     /* Variables for the deform algorithm */
-    gmx_int64_t     deformref_step;
-    matrix          deformref_box;
+    gmx_int64_t       deformref_step;
+    matrix            deformref_box;
 };
 
+static bool isTemperatureCouplingStep(gmx_int64_t step, const t_inputrec *ir)
+{
+    /* We should only couple after a step where energies were determined (for leapfrog versions)
+       or the step energies are determined, for velocity verlet versions */
+    int offset;
+    if (EI_VV(ir->eI))
+    {
+        offset = 0;
+    }
+    else
+    {
+        offset = 1;
+    }
+    return ir->etc != etcNO &&
+           (ir->nsttcouple == 1 ||
+            do_per_step(step + ir->nsttcouple - offset, ir->nsttcouple));
+}
 
-static void do_update_md(int start, int nrend,
-                         double dt, int nstpcouple,
-                         t_grp_tcstat *tcstat,
-                         double nh_vxi[],
-                         gmx_bool bNEMD, t_grp_acc *gstat, rvec accel[],
-                         ivec nFreeze[],
-                         real invmass[],
-                         unsigned short ptype[], unsigned short cFREEZE[],
-                         unsigned short cACC[], unsigned short cTC[],
-                         rvec x[], rvec xprime[], rvec v[],
-                         rvec f[], matrix M,
-                         gmx_bool bNH, gmx_bool bPR)
+static bool isPressureCouplingStep(gmx_int64_t step, const t_inputrec *ir)
 {
-    double imass, w_dt;
-    int    gf = 0, ga = 0, gt = 0;
-    rvec   vrel;
-    real   vn, vv, va, vb, vnrel;
-    real   lg, vxi = 0, u;
-    int    n, d;
+    GMX_ASSERT(ir->epc != epcMTTK, "MTTK pressure coupling is not handled here");
 
-    if (bNH || bPR)
+    int offset;
+    if (ir->epc == epcBERENDSEN)
     {
-        /* Update with coupling to extended ensembles, used for
-         * Nose-Hoover and Parrinello-Rahman coupling
-         * Nose-Hoover uses the reversible leap-frog integrator from
-         * Holian et al. Phys Rev E 52(3) : 2338, 1995
-         */
-        for (n = start; n < nrend; n++)
+        offset = 0;
+    }
+    else
+    {
+        offset = 1;
+    }
+    /* We should only couple after a step where pressures were determined */
+    return ir->epc != etcNO &&
+           (ir->nstpcouple == 1 ||
+            do_per_step(step + ir->nstpcouple - offset, ir->nstpcouple));
+}
+
+/*! \brief Sets the number of different temperature coupling values */
+enum class NumTempScaleValues
+{
+    single,   //!< Single T-scaling value (either one group or all values =1)
+    multiple  //!< Multiple T-scaling values, need to use T-group indices
+};
+
+/*! \brief Sets if to apply no or diagonal Parrinello-Rahman pressure scaling
+ *
+ * Note that this enum is only used in updateMdLeapfrogSimple(), which does
+ * not handle fully anistropic Parrinello-Rahman scaling, so we only have
+ * options \p no and \p diagonal here and no anistropic option.
+ */
+enum class ApplyParrinelloRahmanVScaling
+{
+    no,       //!< Do not apply velocity scaling (not a PR-coupling run or step)
+    diagonal  //!< Apply velocity scaling using a diagonal matrix
+};
+
+/*! \brief Integrate using leap-frog with T-scaling and optionally diagonal Parrinello-Rahman p-coupling
+ *
+ * \tparam       numTempScaleValues     The number of different T-couple values
+ * \tparam       applyPRVScaling        Apply Parrinello-Rahman velocity scaling
+ * \param[in]    start                  Index of first atom to update
+ * \param[in]    nrend                  Last atom to update: \p nrend - 1
+ * \param[in]    dt                     The time step
+ * \param[in]    dtPressureCouple       Time step for pressure coupling
+ * \param[in]    invMassPerDim          1/mass per atom and dimension
+ * \param[in]    tcstat                 Temperature coupling information
+ * \param[in]    cTC                    T-coupling group index per atom
+ * \param[in]    pRVScaleMatrixDiagonal Parrinello-Rahman v-scale matrix diagonal
+ * \param[in]    x                      Input coordinates
+ * \param[out]   xprime                 Updated coordinates
+ * \param[inout] v                      Velocities
+ * \param[in]    f                      Forces
+ *
+ * We expect this template to get good SIMD acceleration by most compilers,
+ * unlike the more complex general template.
+ * Note that we might get even better SIMD acceleration when we introduce
+ * aligned (and padded) memory, possibly with some hints for the compilers.
+ */
+template<NumTempScaleValues            numTempScaleValues,
+         ApplyParrinelloRahmanVScaling applyPRVScaling>
+static void
+updateMdLeapfrogSimple(int                       start,
+                       int                       nrend,
+                       real                      dt,
+                       real                      dtPressureCouple,
+                       const rvec * gmx_restrict invMassPerDim,
+                       const t_grp_tcstat      * tcstat,
+                       const unsigned short    * cTC,
+                       const rvec                pRVScaleMatrixDiagonal,
+                       const rvec * gmx_restrict x,
+                       rvec       * gmx_restrict xprime,
+                       rvec       * gmx_restrict v,
+                       const rvec * gmx_restrict f)
+{
+    real lambdaGroup;
+
+    if (numTempScaleValues == NumTempScaleValues::single)
+    {
+        lambdaGroup = tcstat[0].lambda;
+    }
+
+    for (int a = start; a < nrend; a++)
+    {
+        if (numTempScaleValues == NumTempScaleValues::multiple)
         {
-            imass = invmass[n];
-            if (cFREEZE)
-            {
-                gf   = cFREEZE[n];
-            }
-            if (cACC)
-            {
-                ga   = cACC[n];
-            }
-            if (cTC)
-            {
-                gt   = cTC[n];
-            }
-            lg   = tcstat[gt].lambda;
-            if (bNH)
+            lambdaGroup = tcstat[cTC[a]].lambda;
+        }
+
+        for (int d = 0; d < DIM; d++)
+        {
+            /* Note that using rvec invMassPerDim results in more efficient
+             * SIMD code, but this increases the cache pressure.
+             * For large systems with PME on the CPU this slows down the
+             * (then already slow) update by 20%. If all data remains in cache,
+             * using rvec is much faster.
+             */
+            real vNew = lambdaGroup*v[a][d] + f[a][d]*invMassPerDim[a][d]*dt;
+
+            if (applyPRVScaling == ApplyParrinelloRahmanVScaling::diagonal)
             {
-                vxi   = nh_vxi[gt];
+                vNew -= dtPressureCouple*pRVScaleMatrixDiagonal[d]*v[a][d];
             }
-            rvec_sub(v[n], gstat[ga].u, vrel);
+            v[a][d]      = vNew;
+            xprime[a][d] = x[a][d] + vNew*dt;
+        }
+    }
+}
 
-            for (d = 0; d < DIM; d++)
-            {
-                if ((ptype[n] != eptVSite) && (ptype[n] != eptShell) && !nFreeze[gf][d])
-                {
-                    vnrel = (lg*vrel[d] + dt*(imass*f[n][d] - 0.5*vxi*vrel[d]
-                                              - nstpcouple*iprod(M[d], vrel)))/(1 + 0.5*vxi*dt);
-                    /* do not scale the mean velocities u */
-                    vn             = gstat[ga].u[d] + accel[ga][d]*dt + vnrel;
-                    v[n][d]        = vn;
-                    xprime[n][d]   = x[n][d]+vn*dt;
-                }
-                else
+/*! \brief Sets the NEMD acceleration type */
+enum class AccelerationType
+{
+    none, group, cosine
+};
+
+/*! \brief Integrate using leap-frog with support for everything
+ *
+ * \tparam       accelerationType       Type of NEMD acceleration
+ * \param[in]    start                  Index of first atom to update
+ * \param[in]    nrend                  Last atom to update: \p nrend - 1
+ * \param[in]    doNoseHoover           If to apply Nose-Hoover T-coupling
+ * \param[in]    dt                     The time step
+ * \param[in]    dtPressureCouple       Time step for pressure coupling, is 0 when no pressure coupling should be applied at this step
+ * \param[in]    ir                     The input parameter record
+ * \param[in]    md                     Atom properties
+ * \param[in]    ekind                  Kinetic energy data
+ * \param[in]    box                    The box dimensions
+ * \param[in]    x                      Input coordinates
+ * \param[out]   xprime                 Updated coordinates
+ * \param[inout] v                      Velocities
+ * \param[in]    f                      Forces
+ * \param[in]    nh_vxi                 Nose-Hoover velocity scaling factors
+ * \param[in]    M                      Parrinello-Rahman scaling matrix
+ */
+template<AccelerationType accelerationType>
+static void
+updateMdLeapfrogGeneral(int                         start,
+                        int                         nrend,
+                        bool                        doNoseHoover,
+                        real                        dt,
+                        real                        dtPressureCouple,
+                        const t_inputrec          * ir,
+                        const t_mdatoms           * md,
+                        const gmx_ekindata_t      * ekind,
+                        const matrix                box,
+                        const rvec   * gmx_restrict x,
+                        rvec         * gmx_restrict xprime,
+                        rvec         * gmx_restrict v,
+                        const rvec   * gmx_restrict f,
+                        const double * gmx_restrict nh_vxi,
+                        const matrix                M)
+{
+    /* This is a version of the leap-frog integrator that supports
+     * all combinations of T-coupling, P-coupling and NEMD.
+     * Nose-Hoover uses the reversible leap-frog integrator from
+     * Holian et al. Phys Rev E 52(3) : 2338, 1995
+     */
+
+    const unsigned short    * cTC           = md->cTC;
+    const t_grp_tcstat      * tcstat        = ekind->tcstat;
+
+    const unsigned short    * cACC          = md->cACC;
+    const rvec              * accel         = ir->opts.acc;
+    const t_grp_acc         * grpstat       = ekind->grpstat;
+
+    const rvec * gmx_restrict invMassPerDim = md->invMassPerDim;
+
+    /* Initialize group values, changed later when multiple groups are used */
+    int  ga       = 0;
+    int  gt       = 0;
+    real factorNH = 0;
+
+    for (int n = start; n < nrend; n++)
+    {
+        if (cTC)
+        {
+            gt  = cTC[n];
+        }
+        real lg = tcstat[gt].lambda;
+
+        rvec vRel;
+        real cosineZ, vCosine;
+#ifdef __INTEL_COMPILER
+#pragma warning( disable : 280 )
+#endif
+        switch (accelerationType)
+        {
+            case AccelerationType::none:
+                copy_rvec(v[n], vRel);
+                break;
+            case AccelerationType::group:
+                if (cACC)
                 {
-                    v[n][d]        = 0.0;
-                    xprime[n][d]   = x[n][d];
+                    ga = cACC[n];
                 }
+                /* Avoid scaling the group velocity */
+                rvec_sub(v[n], grpstat[ga].u, vRel);
+                break;
+            case AccelerationType::cosine:
+                cosineZ = std::cos(x[n][ZZ]*static_cast<real>(M_PI)/box[ZZ][ZZ]);
+                vCosine = cosineZ*ekind->cosacc.vcos;
+                /* Avoid scaling the cosine profile velocity */
+                copy_rvec(v[n], vRel);
+                vRel[XX] -= vCosine;
+                break;
+        }
+
+        if (doNoseHoover)
+        {
+            /* Here we account for multiple time stepping, by increasing
+             * the Nose-Hoover correction by nsttcouple
+             */
+            factorNH = 0.5*ir->nsttcouple*dt*nh_vxi[gt];
+        }
+
+        for (int d = 0; d < DIM; d++)
+        {
+            real vNew =
+                (lg*vRel[d] + (f[n][d]*invMassPerDim[n][d]*dt - factorNH*vRel[d]
+                               - dtPressureCouple*iprod(M[d], vRel)))/(1 + factorNH);
+            switch (accelerationType)
+            {
+                case AccelerationType::none:
+                    break;
+                case AccelerationType::group:
+                    /* Add back the mean velocity and apply acceleration */
+                    vNew += grpstat[ga].u[d] + accel[ga][d]*dt;
+                    break;
+                case AccelerationType::cosine:
+                    if (d == XX)
+                    {
+                        /* Add back the mean velocity and apply acceleration */
+                        vNew += vCosine + cosineZ*ekind->cosacc.cos_accel*dt;
+                    }
+                    break;
             }
+            v[n][d]       = vNew;
+            xprime[n][d]  = x[n][d] + vNew*dt;
+        }
+    }
+}
+
+/*! \brief Handles the Leap-frog MD x and v integration */
+static void do_update_md(int                         start,
+                         int                         nrend,
+                         gmx_int64_t                 step,
+                         real                        dt,
+                         const t_inputrec          * ir,
+                         const t_mdatoms           * md,
+                         const gmx_ekindata_t      * ekind,
+                         const matrix                box,
+                         const rvec   * gmx_restrict x,
+                         rvec         * gmx_restrict xprime,
+                         rvec         * gmx_restrict v,
+                         const rvec   * gmx_restrict f,
+                         const double * gmx_restrict nh_vxi,
+                         const matrix                M)
+{
+    GMX_ASSERT(nrend == start || xprime != x, "For SIMD optimization certain compilers need to have xprime != x");
+
+    /* Note: Berendsen pressure scaling is handled after do_update_md() */
+    bool doTempCouple       = isTemperatureCouplingStep(step, ir);
+    bool doNoseHoover       = (ir->etc == etcNOSEHOOVER && doTempCouple);
+    bool doParrinelloRahman = (ir->epc == epcPARRINELLORAHMAN && isPressureCouplingStep(step, ir));
+    bool doPROffDiagonal    = (doParrinelloRahman && (M[YY][XX] != 0 || M[ZZ][XX] != 0 || M[ZZ][YY] != 0));
+
+    real dtPressureCouple   = (doParrinelloRahman ? ir->nstpcouple*dt : 0);
+
+    /* NEMD (also cosine) acceleration is applied in updateMdLeapFrogGeneral */
+    bool doAcceleration     = (ekind->bNEMD || ekind->cosacc.cos_accel != 0);
+
+    if (doNoseHoover || doPROffDiagonal || doAcceleration)
+    {
+        if (!doAcceleration)
+        {
+            updateMdLeapfrogGeneral<AccelerationType::none>
+                (start, nrend, doNoseHoover, dt, dtPressureCouple,
+                ir, md, ekind, box, x, xprime, v, f, nh_vxi, M);
+        }
+        else if (ekind->bNEMD)
+        {
+            updateMdLeapfrogGeneral<AccelerationType::group>
+                (start, nrend, doNoseHoover, dt, dtPressureCouple,
+                ir, md, ekind, box, x, xprime, v, f, nh_vxi, M);
+        }
+        else
+        {
+            updateMdLeapfrogGeneral<AccelerationType::cosine>
+                (start, nrend, doNoseHoover, dt, dtPressureCouple,
+                ir, md, ekind, box, x, xprime, v, f, nh_vxi, M);
         }
     }
-    else if (cFREEZE != NULL ||
-             nFreeze[0][XX] || nFreeze[0][YY] || nFreeze[0][ZZ] ||
-             bNEMD)
+    else
     {
-        /* Update with Berendsen/v-rescale coupling and freeze or NEMD */
-        for (n = start; n < nrend; n++)
+        /* We determine if we have a single T-coupling lambda value for all
+         * atoms. That allows for better SIMD acceleration in the template.
+         * If we do not do temperature coupling (in the run or this step),
+         * all scaling values are 1, so we effectively have a single value.
+         */
+        bool haveSingleTempScaleValue = (!doTempCouple || ekind->ngtc == 1);
+
+        /* Extract some pointers needed by all cases */
+        const unsigned short *cTC           = md->cTC;
+        const t_grp_tcstat   *tcstat        = ekind->tcstat;
+        const rvec           *invMassPerDim = md->invMassPerDim;
+
+        if (doParrinelloRahman)
         {
-            w_dt = invmass[n]*dt;
-            if (cFREEZE)
-            {
-                gf   = cFREEZE[n];
-            }
-            if (cACC)
+            GMX_ASSERT(!doPROffDiagonal, "updateMdLeapfrogSimple only support diagonal Parrinello-Rahman scaling matrices");
+
+            rvec diagM;
+            for (int d = 0; d < DIM; d++)
             {
-                ga   = cACC[n];
+                diagM[d] = M[d][d];
             }
-            if (cTC)
+
+            if (haveSingleTempScaleValue)
             {
-                gt   = cTC[n];
+                updateMdLeapfrogSimple
+                <NumTempScaleValues::single,
+                 ApplyParrinelloRahmanVScaling::diagonal>
+                    (start, nrend, dt, dtPressureCouple,
+                    invMassPerDim, tcstat, cTC, diagM, x, xprime, v, f);
             }
-            lg   = tcstat[gt].lambda;
-
-            for (d = 0; d < DIM; d++)
+            else
             {
-                vn             = v[n][d];
-                if ((ptype[n] != eptVSite) && (ptype[n] != eptShell) && !nFreeze[gf][d])
-                {
-                    vv             = lg*vn + f[n][d]*w_dt;
-
-                    /* do not scale the mean velocities u */
-                    u              = gstat[ga].u[d];
-                    va             = vv + accel[ga][d]*dt;
-                    vb             = va + (1.0-lg)*u;
-                    v[n][d]        = vb;
-                    xprime[n][d]   = x[n][d]+vb*dt;
-                }
-                else
-                {
-                    v[n][d]        = 0.0;
-                    xprime[n][d]   = x[n][d];
-                }
+                updateMdLeapfrogSimple
+                <NumTempScaleValues::multiple,
+                 ApplyParrinelloRahmanVScaling::diagonal>
+                    (start, nrend, dt, dtPressureCouple,
+                    invMassPerDim, tcstat, cTC, diagM, x, xprime, v, f);
             }
         }
-    }
-    else
-    {
-        /* Plain update with Berendsen/v-rescale coupling */
-        for (n = start; n < nrend; n++)
+        else
         {
-            if ((ptype[n] != eptVSite) && (ptype[n] != eptShell))
+            if (haveSingleTempScaleValue)
             {
-                w_dt = invmass[n]*dt;
-                if (cTC)
-                {
-                    gt = cTC[n];
-                }
-                lg = tcstat[gt].lambda;
-
-                for (d = 0; d < DIM; d++)
-                {
-                    vn           = lg*v[n][d] + f[n][d]*w_dt;
-                    v[n][d]      = vn;
-                    xprime[n][d] = x[n][d] + vn*dt;
-                }
+                updateMdLeapfrogSimple
+                <NumTempScaleValues::single,
+                 ApplyParrinelloRahmanVScaling::no>
+                    (start, nrend, dt, dtPressureCouple,
+                    invMassPerDim, tcstat, cTC, NULL, x, xprime, v, f);
             }
             else
             {
-                for (d = 0; d < DIM; d++)
-                {
-                    v[n][d]        = 0.0;
-                    xprime[n][d]   = x[n][d];
-                }
+                updateMdLeapfrogSimple
+                <NumTempScaleValues::multiple,
+                 ApplyParrinelloRahmanVScaling::no>
+                    (start, nrend, dt, dtPressureCouple,
+                    invMassPerDim, tcstat, cTC, NULL, x, xprime, v, f);
             }
         }
     }
 }
 
-static void do_update_vv_vel(int start, int nrend, double dt,
+static void do_update_vv_vel(int start, int nrend, real dt,
                              rvec accel[], ivec nFreeze[], real invmass[],
                              unsigned short ptype[], unsigned short cFREEZE[],
-                             unsigned short cACC[], rvec v[], rvec f[],
+                             unsigned short cACC[], rvec v[], const rvec f[],
                              gmx_bool bExtended, real veta, real alpha)
 {
-    double w_dt;
     int    gf = 0, ga = 0;
     int    n, d;
-    double g, mv1, mv2;
+    real   g, mv1, mv2;
 
     if (bExtended)
     {
         g        = 0.25*dt*veta*alpha;
-        mv1      = exp(-g);
+        mv1      = std::exp(-g);
         mv2      = gmx::series_sinhx(g);
     }
     else
@@ -282,7 +508,7 @@ static void do_update_vv_vel(int start, int nrend, double dt,
     }
     for (n = start; n < nrend; n++)
     {
-        w_dt = invmass[n]*dt;
+        real w_dt = invmass[n]*dt;
         if (cFREEZE)
         {
             gf   = cFREEZE[n];
@@ -306,21 +532,21 @@ static void do_update_vv_vel(int start, int nrend, double dt,
     }
 } /* do_update_vv_vel */
 
-static void do_update_vv_pos(int start, int nrend, double dt,
+static void do_update_vv_pos(int start, int nrend, real dt,
                              ivec nFreeze[],
                              unsigned short ptype[], unsigned short cFREEZE[],
-                             rvec x[], rvec xprime[], rvec v[],
+                             const rvec x[], rvec xprime[], rvec v[],
                              gmx_bool bExtended, real veta)
 {
     int    gf = 0;
     int    n, d;
-    double g, mr1, mr2;
+    real   g, mr1, mr2;
 
     /* Would it make more sense if Parrinello-Rahman was put here? */
     if (bExtended)
     {
         g        = 0.5*dt*veta;
-        mr1      = exp(g);
+        mr1      = std::exp(g);
         mr2      = gmx::series_sinhx(g);
     }
     else
@@ -351,114 +577,6 @@ static void do_update_vv_pos(int start, int nrend, double dt,
     }
 } /* do_update_vv_pos */
 
-static void do_update_visc(int start, int nrend,
-                           double dt, int nstpcouple,
-                           t_grp_tcstat *tcstat,
-                           double nh_vxi[],
-                           real invmass[],
-                           unsigned short ptype[], unsigned short cTC[],
-                           rvec x[], rvec xprime[], rvec v[],
-                           rvec f[], matrix M, matrix box, real
-                           cos_accel, real vcos,
-                           gmx_bool bNH, gmx_bool bPR)
-{
-    double imass, w_dt;
-    int    gt = 0;
-    real   vn, vc;
-    real   lg, vxi = 0, vv;
-    real   fac, cosz;
-    rvec   vrel;
-    int    n, d;
-
-    fac = 2*M_PI/(box[ZZ][ZZ]);
-
-    if (bNH || bPR)
-    {
-        /* Update with coupling to extended ensembles, used for
-         * Nose-Hoover and Parrinello-Rahman coupling
-         */
-        for (n = start; n < nrend; n++)
-        {
-            imass = invmass[n];
-            if (cTC)
-            {
-                gt   = cTC[n];
-            }
-            lg   = tcstat[gt].lambda;
-            cosz = cos(fac*x[n][ZZ]);
-
-            copy_rvec(v[n], vrel);
-
-            vc            = cosz*vcos;
-            vrel[XX]     -= vc;
-            if (bNH)
-            {
-                vxi        = nh_vxi[gt];
-            }
-            for (d = 0; d < DIM; d++)
-            {
-                if ((ptype[n] != eptVSite) && (ptype[n] != eptShell))
-                {
-                    vn  = (lg*vrel[d] + dt*(imass*f[n][d] - 0.5*vxi*vrel[d]
-                                            - nstpcouple*iprod(M[d], vrel)))/(1 + 0.5*vxi*dt);
-                    if (d == XX)
-                    {
-                        vn += vc + dt*cosz*cos_accel;
-                    }
-                    v[n][d]        = vn;
-                    xprime[n][d]   = x[n][d]+vn*dt;
-                }
-                else
-                {
-                    xprime[n][d]   = x[n][d];
-                }
-            }
-        }
-    }
-    else
-    {
-        /* Classic version of update, used with berendsen coupling */
-        for (n = start; n < nrend; n++)
-        {
-            w_dt = invmass[n]*dt;
-            if (cTC)
-            {
-                gt   = cTC[n];
-            }
-            lg   = tcstat[gt].lambda;
-            cosz = cos(fac*x[n][ZZ]);
-
-            for (d = 0; d < DIM; d++)
-            {
-                vn             = v[n][d];
-
-                if ((ptype[n] != eptVSite) && (ptype[n] != eptShell))
-                {
-                    if (d == XX)
-                    {
-                        vc           = cosz*vcos;
-                        /* Do not scale the cosine velocity profile */
-                        vv           = vc + lg*(vn - vc + f[n][d]*w_dt);
-                        /* Add the cosine accelaration profile */
-                        vv          += dt*cosz*cos_accel;
-                    }
-                    else
-                    {
-                        vv           = lg*(vn + f[n][d]*w_dt);
-                    }
-                    v[n][d]        = vv;
-                    xprime[n][d]   = x[n][d]+vv*dt;
-                }
-                else
-                {
-                    v[n][d]        = 0.0;
-                    xprime[n][d]   = x[n][d];
-                }
-            }
-        }
-    }
-}
-
 static gmx_stochd_t *init_stochd(const t_inputrec *ir)
 {
     gmx_stochd_t   *sd;
@@ -483,7 +601,7 @@ static gmx_stochd_t *init_stochd(const t_inputrec *ir)
         {
             if (opts->tau_t[gt] > 0)
             {
-                sdc[gt].em  = exp(-ir->delta_t/opts->tau_t[gt]);
+                sdc[gt].em  = std::exp(-ir->delta_t/opts->tau_t[gt]);
             }
             else
             {
@@ -550,9 +668,7 @@ void update_temperature_constants(gmx_update_t *upd, const t_inputrec *ir)
 
 gmx_update_t *init_update(const t_inputrec *ir)
 {
-    gmx_update_t *upd;
-
-    snew(upd, 1);
+    gmx_update_t *upd = new(gmx_update_t);
 
     if (ir->eI == eiBD || EI_SD(ir->eI) || ir->etc == etcVRESCALE || ETC_ANDERSEN(ir->etc))
     {
@@ -561,31 +677,27 @@ gmx_update_t *init_update(const t_inputrec *ir)
 
     update_temperature_constants(upd, ir);
 
-    upd->xp        = NULL;
-    upd->xp_nalloc = 0;
+    upd->xp.resize(0);
 
     return upd;
 }
 
-void update_realloc(gmx_update_t *upd, int state_nalloc)
+void update_realloc(gmx_update_t *upd, int natoms)
 {
     GMX_ASSERT(upd, "upd must be allocated before its fields can be reallocated");
-    if (state_nalloc > upd->xp_nalloc)
-    {
-        upd->xp_nalloc = state_nalloc;
-        /* We need to allocate one element extra, since we might use
-         * (unaligned) 4-wide SIMD loads to access rvec entries. */
-        srenew(upd->xp, upd->xp_nalloc + 1);
-    }
+
+    /* We need to allocate one element extra, since we might use
+     * (unaligned) 4-wide SIMD loads to access rvec entries. */
+    upd->xp.resize(natoms + 1);
 }
 
 static void do_update_sd1(gmx_stochd_t *sd,
-                          int start, int nrend, double dt,
+                          int start, int nrend, real dt,
                           rvec accel[], ivec nFreeze[],
                           real invmass[], unsigned short ptype[],
                           unsigned short cFREEZE[], unsigned short cACC[],
                           unsigned short cTC[],
-                          rvec x[], rvec xprime[], rvec v[], rvec f[],
+                          const rvec x[], rvec xprime[], rvec v[], const rvec f[],
                           gmx_bool bDoConstr,
                           gmx_bool bFirstHalfConstr,
                           gmx_int64_t step, int seed, int* gatindex)
@@ -724,12 +836,12 @@ static void do_update_sd1(gmx_stochd_t *sd,
     }
 }
 
-static void do_update_bd(int start, int nrend, double dt,
+static void do_update_bd(int start, int nrend, real dt,
                          ivec nFreeze[],
                          real invmass[], unsigned short ptype[],
                          unsigned short cFREEZE[], unsigned short cTC[],
-                         rvec x[], rvec xprime[], rvec v[],
-                         rvec f[], real friction_coefficient,
+                         const rvec x[], rvec xprime[], rvec v[],
+                         const rvec f[], real friction_coefficient,
                          real *rf, gmx_int64_t step, int seed,
                          int* gatindex)
 {
@@ -791,17 +903,23 @@ static void do_update_bd(int start, int nrend, double dt,
 }
 
 static void dump_it_all(FILE gmx_unused *fp, const char gmx_unused *title,
-                        int gmx_unused natoms, rvec gmx_unused x[], rvec gmx_unused xp[],
-                        rvec gmx_unused v[], rvec gmx_unused f[])
+                        int gmx_unused natoms,
+                        const gmx_unused PaddedRVecVector *x,
+                        const gmx_unused PaddedRVecVector *xp,
+                        const gmx_unused PaddedRVecVector *v,
+                        const gmx_unused PaddedRVecVector *f)
 {
 #ifdef DEBUG
     if (fp)
     {
         fprintf(fp, "%s\n", title);
-        pr_rvecs(fp, 0, "x", x, natoms);
-        pr_rvecs(fp, 0, "xp", xp, natoms);
-        pr_rvecs(fp, 0, "v", v, natoms);
-        pr_rvecs(fp, 0, "f", f, natoms);
+        pr_rvecs(fp, 0, "x", as_rvec_array(x->data()), natoms);
+        pr_rvecs(fp, 0, "xp", as_rvec_array(xp->data()), natoms);
+        pr_rvecs(fp, 0, "v", as_rvec_array(v->data()), natoms);
+        if (f != NULL)
+        {
+            pr_rvecs(fp, 0, "f", as_rvec_array(f->data()), natoms);
+        }
     }
 #endif
 }
@@ -1000,11 +1118,11 @@ void calc_ke_part(t_state *state, t_grpopts *opts, t_mdatoms *md,
 {
     if (ekind->cosacc.cos_accel == 0)
     {
-        calc_ke_part_normal(state->v, opts, md, ekind, nrnb, bEkinAveVel);
+        calc_ke_part_normal(as_rvec_array(state->v.data()), opts, md, ekind, nrnb, bEkinAveVel);
     }
     else
     {
-        calc_ke_part_visc(state->box, state->x, state->v, opts, md, ekind, nrnb, bEkinAveVel);
+        calc_ke_part_visc(state->box, as_rvec_array(state->x.data()), as_rvec_array(state->v.data()), opts, md, ekind, nrnb, bEkinAveVel);
     }
 }
 
@@ -1014,9 +1132,9 @@ extern void init_ekinstate(ekinstate_t *ekinstate, const t_inputrec *ir)
     snew(ekinstate->ekinh, ekinstate->ekin_n);
     snew(ekinstate->ekinf, ekinstate->ekin_n);
     snew(ekinstate->ekinh_old, ekinstate->ekin_n);
-    snew(ekinstate->ekinscalef_nhc, ekinstate->ekin_n);
-    snew(ekinstate->ekinscaleh_nhc, ekinstate->ekin_n);
-    snew(ekinstate->vscale_nhc, ekinstate->ekin_n);
+    ekinstate->ekinscalef_nhc.resize(ekinstate->ekin_n);
+    ekinstate->ekinscaleh_nhc.resize(ekinstate->ekin_n);
+    ekinstate->vscale_nhc.resize(ekinstate->ekin_n);
     ekinstate->dekindl = 0;
     ekinstate->mvcos   = 0;
 }
@@ -1157,33 +1275,18 @@ void update_tcouple(gmx_int64_t       step,
                     t_mdatoms        *md)
 
 {
-    gmx_bool   bTCouple = FALSE;
-    real       dttc;
-    int        i, offset;
+    bool doTemperatureCoupling = false;
 
     /* if using vv with trotter decomposition methods, we do this elsewhere in the code */
-    if (inputrec->etc != etcNO &&
-        !(inputrecNvtTrotter(inputrec) || inputrecNptTrotter(inputrec) || inputrecNphTrotter(inputrec)))
+    if (!(EI_VV(inputrec->eI) &&
+          (inputrecNvtTrotter(inputrec) || inputrecNptTrotter(inputrec) || inputrecNphTrotter(inputrec))))
     {
-        /* We should only couple after a step where energies were determined (for leapfrog versions)
-           or the step energies are determined, for velocity verlet versions */
-
-        if (EI_VV(inputrec->eI))
-        {
-            offset = 0;
-        }
-        else
-        {
-            offset = 1;
-        }
-        bTCouple = (inputrec->nsttcouple == 1 ||
-                    do_per_step(step+inputrec->nsttcouple-offset,
-                                inputrec->nsttcouple));
+        doTemperatureCoupling = isTemperatureCouplingStep(step, inputrec);
     }
 
-    if (bTCouple)
+    if (doTemperatureCoupling)
     {
-        dttc = inputrec->nsttcouple*inputrec->delta_t;
+        real dttc = inputrec->nsttcouple*inputrec->delta_t;
 
         switch (inputrec->etc)
         {
@@ -1194,85 +1297,48 @@ void update_tcouple(gmx_int64_t       step,
                 break;
             case etcNOSEHOOVER:
                 nosehoover_tcoupl(&(inputrec->opts), ekind, dttc,
-                                  state->nosehoover_xi, state->nosehoover_vxi, MassQ);
+                                  state->nosehoover_xi.data(), state->nosehoover_vxi.data(), MassQ);
                 break;
             case etcVRESCALE:
                 vrescale_tcoupl(inputrec, step, ekind, dttc,
-                                state->therm_integral);
+                                state->therm_integral.data());
                 break;
         }
         /* rescale in place here */
         if (EI_VV(inputrec->eI))
         {
-            rescale_velocities(ekind, md, 0, md->homenr, state->v);
+            rescale_velocities(ekind, md, 0, md->homenr, as_rvec_array(state->v.data()));
         }
     }
     else
     {
         /* Set the T scaling lambda to 1 to have no scaling */
-        for (i = 0; (i < inputrec->opts.ngtc); i++)
+        for (int i = 0; (i < inputrec->opts.ngtc); i++)
         {
             ekind->tcstat[i].lambda = 1.0;
         }
     }
 }
 
-void update_pcouple(FILE             *fplog,
-                    gmx_int64_t       step,
-                    t_inputrec       *inputrec,
-                    t_state          *state,
-                    matrix            pcoupl_mu,
-                    matrix            M,
-                    gmx_bool          bInitStep)
+void update_pcouple_before_coordinates(FILE             *fplog,
+                                       gmx_int64_t       step,
+                                       const t_inputrec *inputrec,
+                                       t_state          *state,
+                                       matrix            parrinellorahmanMu,
+                                       matrix            M,
+                                       gmx_bool          bInitStep)
 {
-    gmx_bool   bPCouple = FALSE;
-    real       dtpc     = 0;
-    int        i;
-
-    /* if using Trotter pressure, we do this in coupling.c, so we leave it false. */
-    if (inputrec->epc != epcNO && (!(inputrecNptTrotter(inputrec) || inputrecNphTrotter(inputrec))))
-    {
-        /* We should only couple after a step where energies were determined */
-        bPCouple = (inputrec->nstpcouple == 1 ||
-                    do_per_step(step+inputrec->nstpcouple-1,
-                                inputrec->nstpcouple));
-    }
-
-    clear_mat(pcoupl_mu);
-    for (i = 0; i < DIM; i++)
-    {
-        pcoupl_mu[i][i] = 1.0;
-    }
-
-    clear_mat(M);
-
-    if (bPCouple)
+    /* Berendsen P-coupling is completely handled after the coordinate update.
+     * Trotter P-coupling is handled by separate calls to trotter_update().
+     */
+    if (inputrec->epc == epcPARRINELLORAHMAN &&
+        isPressureCouplingStep(step, inputrec))
     {
-        dtpc = inputrec->nstpcouple*inputrec->delta_t;
+        real dtpc = inputrec->nstpcouple*inputrec->delta_t;
 
-        switch (inputrec->epc)
-        {
-            /* We can always pcoupl, even if we did not sum the energies
-             * the previous step, since state->pres_prev is only updated
-             * when the energies have been summed.
-             */
-            case (epcNO):
-                break;
-            case (epcBERENDSEN):
-                if (!bInitStep)
-                {
-                    berendsen_pcoupl(fplog, step, inputrec, dtpc, state->pres_prev, state->box,
-                                     pcoupl_mu);
-                }
-                break;
-            case (epcPARRINELLORAHMAN):
-                parrinellorahman_pcoupl(fplog, step, inputrec, dtpc, state->pres_prev,
-                                        state->box, state->box_rel, state->boxv,
-                                        M, pcoupl_mu, bInitStep);
-                break;
-            default:
-                break;
-        }
+        parrinellorahman_pcoupl(fplog, step, inputrec, dtpc, state->pres_prev,
+                                state->box, state->box_rel, state->boxv,
+                                M, parrinellorahmanMu, bInitStep);
     }
 }
 
@@ -1284,7 +1350,7 @@ void update_constraints(FILE             *fplog,
                         t_state          *state,
                         gmx_bool          bMolPBC,
                         t_graph          *graph,
-                        rvec              force[],   /* forces on home particles */
+                        PaddedRVecVector *force,     /* forces on home particles */
                         t_idef           *idef,
                         tensor            vir_part,
                         t_commrec        *cr,
@@ -1296,8 +1362,6 @@ void update_constraints(FILE             *fplog,
                         gmx_bool          bCalcVir)
 {
     gmx_bool             bLastStep, bLog = FALSE, bEner = FALSE, bDoConstr = FALSE;
-    double               dt;
-    int                  start, homenr, nrend, i;
     tensor               vir_con;
     int                  nth, th;
 
@@ -1313,11 +1377,18 @@ void update_constraints(FILE             *fplog,
     /* for now, SD update is here -- though it really seems like it
        should be reformulated as a velocity verlet method, since it has two parts */
 
-    start  = 0;
-    homenr = md->homenr;
-    nrend  = start+homenr;
+    int  start  = 0;
+    int  homenr = md->homenr;
+    int  nrend  = start+homenr;
 
-    dt   = inputrec->delta_t;
+    /* Cast delta_t from double to real to make the integrators faster.
+     * The only reason for having delta_t double is to get accurate values
+     * for t=delta_t*step when step is larger than float precision.
+     * For integration dt the accuracy of real suffices, since with
+     * integral += dt*integrand the increment is nearly always (much) smaller
+     * than the integral (and the integrand has real precision).
+     */
+    real dt     = inputrec->delta_t;
 
     /*
      *  Steps (7C, 8C)
@@ -1344,7 +1415,7 @@ void update_constraints(FILE             *fplog,
         {
             constrain(NULL, bLog, bEner, constr, idef,
                       inputrec, cr, step, 1, 1.0, md,
-                      state->x, state->v, state->v,
+                      as_rvec_array(state->x.data()), as_rvec_array(state->v.data()), as_rvec_array(state->v.data()),
                       bMolPBC, state->box,
                       state->lambda[efptBONDED], dvdlambda,
                       NULL, bCalcVir ? &vir_con : NULL, nrnb, econqVeloc);
@@ -1353,17 +1424,17 @@ void update_constraints(FILE             *fplog,
         {
             constrain(NULL, bLog, bEner, constr, idef,
                       inputrec, cr, step, 1, 1.0, md,
-                      state->x, upd->xp, NULL,
+                      as_rvec_array(state->x.data()), as_rvec_array(upd->xp.data()), NULL,
                       bMolPBC, state->box,
                       state->lambda[efptBONDED], dvdlambda,
-                      state->v, bCalcVir ? &vir_con : NULL, nrnb, econqCoord);
+                      as_rvec_array(state->v.data()), bCalcVir ? &vir_con : NULL, nrnb, econqCoord);
         }
         wallcycle_stop(wcycle, ewcCONSTR);
 
         where();
 
         dump_it_all(fplog, "After Shake",
-                    state->natoms, state->x, upd->xp, state->v, force);
+                    state->natoms, &state->x, &upd->xp, &state->v, force);
 
         if (bCalcVir)
         {
@@ -1399,7 +1470,7 @@ void update_constraints(FILE             *fplog,
                               inputrec->opts.acc, inputrec->opts.nFreeze,
                               md->invmass, md->ptype,
                               md->cFREEZE, md->cACC, md->cTC,
-                              state->x, upd->xp, state->v, force,
+                              as_rvec_array(state->x.data()), as_rvec_array(upd->xp.data()), as_rvec_array(state->v.data()), as_rvec_array(force->data()),
                               bDoConstr, FALSE,
                               step, inputrec->ld_seed,
                               DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL);
@@ -1416,10 +1487,10 @@ void update_constraints(FILE             *fplog,
 
             constrain(NULL, bLog, bEner, constr, idef,
                       inputrec, cr, step, 1, 0.5, md,
-                      state->x, upd->xp, NULL,
+                      as_rvec_array(state->x.data()), as_rvec_array(upd->xp.data()), NULL,
                       bMolPBC, state->box,
                       state->lambda[efptBONDED], dvdlambda,
-                      state->v, NULL, nrnb, econqCoord);
+                      as_rvec_array(state->v.data()), NULL, nrnb, econqCoord);
 
             wallcycle_stop(wcycle, ewcCONSTR);
         }
@@ -1475,7 +1546,7 @@ void update_constraints(FILE             *fplog,
 
         if (graph && (graph->nnodes > 0))
         {
-            unshift_x(graph, state->box, state->x, upd->xp);
+            unshift_x(graph, state->box, as_rvec_array(state->x.data()), as_rvec_array(upd->xp.data()));
             if (TRICLINIC(state->box))
             {
                 inc_nrnb(nrnb, eNR_SHIFTX, 2*graph->nnodes);
@@ -1487,42 +1558,42 @@ void update_constraints(FILE             *fplog,
         }
         else
         {
+            /* The copy is performance sensitive, so use a bare pointer */
+            rvec *xp = as_rvec_array(upd->xp.data());
 #ifndef __clang_analyzer__
             // cppcheck-suppress unreadVariable
             nth = gmx_omp_nthreads_get(emntUpdate);
 #endif
 #pragma omp parallel for num_threads(nth) schedule(static)
-            for (i = start; i < nrend; i++)
+            for (int i = start; i < nrend; i++)
             {
                 // Trivial statement, does not throw
-                copy_rvec(upd->xp[i], state->x[i]);
+                copy_rvec(xp[i], state->x[i]);
             }
         }
         wallcycle_stop(wcycle, ewcUPDATE);
 
         dump_it_all(fplog, "After unshift",
-                    state->natoms, state->x, upd->xp, state->v, force);
+                    state->natoms, &state->x, &upd->xp, &state->v, force);
     }
 /* ############# END the update of velocities and positions ######### */
 }
 
-void update_box(FILE             *fplog,
-                gmx_int64_t       step,
-                t_inputrec       *inputrec,  /* input record and box stuff     */
-                t_mdatoms        *md,
-                t_state          *state,
-                rvec              force[],   /* forces on home particles */
-                matrix            pcoupl_mu,
-                t_nrnb           *nrnb,
-                gmx_update_t     *upd)
+void update_pcouple_after_coordinates(FILE             *fplog,
+                                      gmx_int64_t       step,
+                                      const t_inputrec *inputrec,
+                                      const t_mdatoms  *md,
+                                      const matrix      pressure,
+                                      const matrix      parrinellorahmanMu,
+                                      t_state          *state,
+                                      t_nrnb           *nrnb,
+                                      gmx_update_t     *upd)
 {
-    double               dt;
-    int                  start, homenr, i, n, m;
+    int  start  = 0;
+    int  homenr = md->homenr;
 
-    start  = 0;
-    homenr = md->homenr;
-
-    dt = inputrec->delta_t;
+    /* Cast to real for faster code, no loss in precision (see comment above) */
+    real dt     = inputrec->delta_t;
 
     where();
 
@@ -1532,35 +1603,39 @@ void update_box(FILE             *fplog,
         case (epcNO):
             break;
         case (epcBERENDSEN):
-            /* We should only scale after a step where the pressure (kinetic
-             * energy and virial) was calculated. This happens after the
-             * coordinate update, whereas the current routine is called before
-             * that, so we scale when step % nstpcouple = 1 instead of 0.
-             */
-            if (inputrec->nstpcouple == 1 || (step % inputrec->nstpcouple == 1))
+            if (isPressureCouplingStep(step, inputrec))
             {
-                berendsen_pscale(inputrec, pcoupl_mu, state->box, state->box_rel,
-                                 start, homenr, state->x, md->cFREEZE, nrnb);
+                real   dtpc = inputrec->nstpcouple*dt;
+                matrix mu;
+                berendsen_pcoupl(fplog, step, inputrec, dtpc, pressure, state->box,
+                                 mu);
+                berendsen_pscale(inputrec, mu, state->box, state->box_rel,
+                                 start, homenr, as_rvec_array(state->x.data()),
+                                 md->cFREEZE, nrnb);
             }
             break;
         case (epcPARRINELLORAHMAN):
-            /* The box velocities were updated in do_pr_pcoupl in the update
-             * iteration, but we dont change the box vectors until we get here
-             * since we need to be able to shift/unshift above.
-             */
-            for (i = 0; i < DIM; i++)
+            if (isPressureCouplingStep(step, inputrec))
             {
-                for (m = 0; m <= i; m++)
+                /* The box velocities were updated in do_pr_pcoupl,
+                 * but we dont change the box vectors until we get here
+                 * since we need to be able to shift/unshift above.
+                 */
+                real dtpc = inputrec->nstpcouple*dt;
+                for (int i = 0; i < DIM; i++)
                 {
-                    state->box[i][m] += dt*state->boxv[i][m];
+                    for (int m = 0; m <= i; m++)
+                    {
+                        state->box[i][m] += dtpc*state->boxv[i][m];
+                    }
                 }
-            }
-            preserve_box_shape(inputrec, state->box_rel, state->box);
+                preserve_box_shape(inputrec, state->box_rel, state->box);
 
-            /* Scale the coordinates */
-            for (n = start; (n < start+homenr); n++)
-            {
-                tmvmul_ur0(pcoupl_mu, state->x[n], state->x[n]);
+                /* Scale the coordinates */
+                for (int n = start; n < start + homenr; n++)
+                {
+                    tmvmul_ur0(parrinellorahmanMu, state->x[n], state->x[n]);
+                }
             }
             break;
         case (epcMTTK):
@@ -1571,7 +1646,7 @@ void update_box(FILE             *fplog,
                        ln V_new = ln V_old + 3*dt*veta => V_new = V_old*exp(3*dt*veta) =>
                        Side length scales as exp(veta*dt) */
 
-                    msmul(state->box, exp(state->veta*dt), state->box);
+                    msmul(state->box, std::exp(state->veta*dt), state->box);
 
                     /* Relate veta to boxv.  veta = d(eta)/dT = (1/DIM)*1/V dV/dT.
                        o               If we assume isotropic scaling, and box length scaling
@@ -1594,11 +1669,11 @@ void update_box(FILE             *fplog,
 
     if (inputrecDeform(inputrec))
     {
-        deform(upd, start, homenr, state->x, state->box, inputrec, step);
+        deform(upd, start, homenr, as_rvec_array(state->x.data()), state->box, inputrec, step);
     }
     where();
     dump_it_all(fplog, "After update",
-                state->natoms, state->x, upd->xp, state->v, force);
+                state->natoms, &state->x, &upd->xp, &state->v, NULL);
 }
 
 void update_coords(FILE             *fplog,
@@ -1606,7 +1681,7 @@ void update_coords(FILE             *fplog,
                    t_inputrec       *inputrec,  /* input record and box stuff  */
                    t_mdatoms        *md,
                    t_state          *state,
-                   rvec             *f,    /* forces on home particles */
+                   PaddedRVecVector *f,    /* forces on home particles */
                    t_fcdata         *fcd,
                    gmx_ekindata_t   *ekind,
                    matrix            M,
@@ -1615,12 +1690,7 @@ void update_coords(FILE             *fplog,
                    t_commrec        *cr, /* these shouldn't be here -- need to think about it */
                    gmx_constr_t      constr)
 {
-    gmx_bool          bNH, bPR, bDoConstr = FALSE;
-    double            dt, alpha;
-    int               start, homenr, nrend;
-    int               nth, th;
-
-    bDoConstr = (NULL != constr);
+    gmx_bool bDoConstr = (NULL != constr);
 
     /* Running the velocity half does nothing except for velocity verlet */
     if ((UpdatePart == etrtVELOCITY1 || UpdatePart == etrtVELOCITY2) &&
@@ -1629,11 +1699,12 @@ void update_coords(FILE             *fplog,
         gmx_incons("update_coords called for velocity without VV integrator");
     }
 
-    start  = 0;
-    homenr = md->homenr;
-    nrend  = start+homenr;
+    int  start  = 0;
+    int  homenr = md->homenr;
+    int  nrend  = start+homenr;
 
-    dt   = inputrec->delta_t;
+    /* Cast to real for faster code, no loss in precision (see comment above) */
+    real dt     = inputrec->delta_t;
 
     /* We need to update the NMR restraint history when time averaging is used */
     if (state->flags & (1<<estDISRE_RM3TAV))
@@ -1645,19 +1716,15 @@ void update_coords(FILE             *fplog,
         update_orires_history(fcd, &state->hist);
     }
 
-
-    bNH = inputrec->etc == etcNOSEHOOVER;
-    bPR = ((inputrec->epc == epcPARRINELLORAHMAN) || (inputrec->epc == epcMTTK));
-
     /* ############# START The update of velocities and positions ######### */
     where();
     dump_it_all(fplog, "Before update",
-                state->natoms, state->x, upd->xp, state->v, f);
+                state->natoms, &state->x, &upd->xp, &state->v, f);
 
-    nth = gmx_omp_nthreads_get(emntUpdate);
+    int nth = gmx_omp_nthreads_get(emntUpdate);
 
-#pragma omp parallel for num_threads(nth) schedule(static) private(alpha)
-    for (th = 0; th < nth; th++)
+#pragma omp parallel for num_threads(nth) schedule(static)
+    for (int th = 0; th < nth; th++)
     {
         try
         {
@@ -1666,33 +1733,18 @@ void update_coords(FILE             *fplog,
             start_th = start + ((nrend-start)* th   )/nth;
             end_th   = start + ((nrend-start)*(th+1))/nth;
 
+            const rvec *x_rvec  = as_rvec_array(state->x.data());
+            rvec       *xp_rvec = as_rvec_array(upd->xp.data());
+            rvec       *v_rvec  = as_rvec_array(state->v.data());
+            const rvec *f_rvec  = as_rvec_array(f->data());
+
             switch (inputrec->eI)
             {
                 case (eiMD):
-                    if (ekind->cosacc.cos_accel == 0)
-                    {
-                        do_update_md(start_th, end_th,
-                                     dt, inputrec->nstpcouple,
-                                     ekind->tcstat, state->nosehoover_vxi,
-                                     ekind->bNEMD, ekind->grpstat, inputrec->opts.acc,
-                                     inputrec->opts.nFreeze,
-                                     md->invmass, md->ptype,
-                                     md->cFREEZE, md->cACC, md->cTC,
-                                     state->x, upd->xp, state->v, f, M,
-                                     bNH, bPR);
-                    }
-                    else
-                    {
-                        do_update_visc(start_th, end_th,
-                                       dt, inputrec->nstpcouple,
-                                       ekind->tcstat, state->nosehoover_vxi,
-                                       md->invmass, md->ptype,
-                                       md->cTC, state->x, upd->xp, state->v, f, M,
-                                       state->box,
-                                       ekind->cosacc.cos_accel,
-                                       ekind->cosacc.vcos,
-                                       bNH, bPR);
-                    }
+                    do_update_md(start_th, end_th, step, dt,
+                                 inputrec, md, ekind, state->box,
+                                 x_rvec, xp_rvec, v_rvec, f_rvec,
+                                 state->nosehoover_vxi.data(), M);
                     break;
                 case (eiSD1):
                     /* With constraints, the SD1 update is done in 2 parts */
@@ -1701,7 +1753,7 @@ void update_coords(FILE             *fplog,
                                   inputrec->opts.acc, inputrec->opts.nFreeze,
                                   md->invmass, md->ptype,
                                   md->cFREEZE, md->cACC, md->cTC,
-                                  state->x, upd->xp, state->v, f,
+                                  x_rvec, xp_rvec, v_rvec, f_rvec,
                                   bDoConstr, TRUE,
                                   step, inputrec->ld_seed, DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL);
                     break;
@@ -1709,14 +1761,20 @@ void update_coords(FILE             *fplog,
                     do_update_bd(start_th, end_th, dt,
                                  inputrec->opts.nFreeze, md->invmass, md->ptype,
                                  md->cFREEZE, md->cTC,
-                                 state->x, upd->xp, state->v, f,
+                                 x_rvec, xp_rvec, v_rvec, f_rvec,
                                  inputrec->bd_fric,
                                  upd->sd->bd_rf,
                                  step, inputrec->ld_seed, DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL);
                     break;
                 case (eiVV):
                 case (eiVVAK):
-                    alpha = 1.0 + DIM/((double)inputrec->opts.nrdf[0]); /* assuming barostat coupled to group 0. */
+                {
+                    gmx_bool bExtended = (inputrec->etc == etcNOSEHOOVER ||
+                                          inputrec->epc == epcPARRINELLORAHMAN ||
+                                          inputrec->epc == epcMTTK);
+
+                    /* assuming barostat coupled to group 0 */
+                    real alpha = 1.0 + DIM/static_cast<real>(inputrec->opts.nrdf[0]);
                     switch (UpdatePart)
                     {
                         case etrtVELOCITY1:
@@ -1725,18 +1783,19 @@ void update_coords(FILE             *fplog,
                                              inputrec->opts.acc, inputrec->opts.nFreeze,
                                              md->invmass, md->ptype,
                                              md->cFREEZE, md->cACC,
-                                             state->v, f,
-                                             (bNH || bPR), state->veta, alpha);
+                                             v_rvec, f_rvec,
+                                             bExtended, state->veta, alpha);
                             break;
                         case etrtPOSITION:
                             do_update_vv_pos(start_th, end_th, dt,
                                              inputrec->opts.nFreeze,
                                              md->ptype, md->cFREEZE,
-                                             state->x, upd->xp, state->v,
-                                             (bNH || bPR), state->veta);
+                                             x_rvec, xp_rvec, v_rvec,
+                                             bExtended, state->veta);
                             break;
                     }
                     break;
+                }
                 default:
                     gmx_fatal(FARGS, "Don't know how to update coordinates");
                     break;
index 7abef4add28c53695464a4da855c511daf685b26..0cd7b74d1819bec05d1684cc20b0d3cde37f5396 100644 (file)
@@ -38,6 +38,7 @@
 #define GMX_MDLIB_UPDATE_H
 
 #include "gromacs/math/vectypes.h"
+#include "gromacs/mdtypes/state.h"
 #include "gromacs/timing/wallcycle.h"
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
@@ -70,7 +71,7 @@ void update_temperature_constants(gmx_update_t *upd, const t_inputrec *ir);
 
 /* Update the size of per-atom arrays (e.g. after DD re-partitioning,
    which might increase the number of home atoms). */
-void update_realloc(gmx_update_t *upd, int state_nalloc);
+void update_realloc(gmx_update_t *upd, int natoms);
 
 /* Store the box at step step
  * as a reference state for simulations with box deformation.
@@ -86,20 +87,36 @@ void update_tcouple(gmx_int64_t       step,
                     t_mdatoms        *md
                     );
 
-void update_pcouple(FILE             *fplog,
-                    gmx_int64_t       step,
-                    t_inputrec       *inputrec,
-                    t_state          *state,
-                    matrix            pcoupl_mu,
-                    matrix            M,
-                    gmx_bool          bInitStep);
+/* Update Parrinello-Rahman, to be called before the coordinate update */
+void update_pcouple_before_coordinates(FILE             *fplog,
+                                       gmx_int64_t       step,
+                                       const t_inputrec *inputrec,
+                                       t_state          *state,
+                                       matrix            parrinellorahmanMu,
+                                       matrix            M,
+                                       gmx_bool          bInitStep);
+
+/* Update the box, to be called after the coordinate update.
+ * For Berendsen P-coupling, also calculates the scaling factor
+ * and scales the coordinates.
+ * When the deform option is used, scales coordinates and box here.
+ */
+void update_pcouple_after_coordinates(FILE             *fplog,
+                                      gmx_int64_t       step,
+                                      const t_inputrec *inputrec,
+                                      const t_mdatoms  *md,
+                                      const matrix      pressure,
+                                      const matrix      parrinellorahmanMu,
+                                      t_state          *state,
+                                      t_nrnb           *nrnb,
+                                      gmx_update_t     *upd);
 
 void update_coords(FILE              *fplog,
                    gmx_int64_t        step,
                    t_inputrec        *inputrec, /* input record and box stuff  */
                    t_mdatoms         *md,
                    t_state           *state,
-                   rvec              *f, /* forces on home particles */
+                   PaddedRVecVector  *f, /* forces on home particles */
                    t_fcdata          *fcd,
                    gmx_ekindata_t    *ekind,
                    matrix             M,
@@ -120,7 +137,7 @@ void update_constraints(FILE              *fplog,
                         t_state           *state,
                         gmx_bool           bMolPBC,
                         t_graph           *graph,
-                        rvec               force[], /* forces on home particles */
+                        PaddedRVecVector  *force, /* forces on home particles */
                         t_idef            *idef,
                         tensor             vir_part,
                         t_commrec         *cr,
@@ -133,17 +150,6 @@ void update_constraints(FILE              *fplog,
 
 /* Return TRUE if OK, FALSE in case of Shake Error */
 
-void update_box(FILE             *fplog,
-                gmx_int64_t       step,
-                t_inputrec       *inputrec, /* input record and box stuff      */
-                t_mdatoms        *md,
-                t_state          *state,
-                rvec              force[], /* forces on home particles */
-                matrix            pcoupl_mu,
-                t_nrnb           *nrnb,
-                gmx_update_t     *upd);
-/* Return TRUE if OK, FALSE in case of Shake Error */
-
 void calc_ke_part(t_state *state, t_grpopts *opts, t_mdatoms *md,
                   gmx_ekindata_t *ekind, t_nrnb *nrnb, gmx_bool bEkinAveVel);
 /*
@@ -183,17 +189,13 @@ void andersen_tcoupl(t_inputrec *ir, gmx_int64_t step,
 void nosehoover_tcoupl(t_grpopts *opts, gmx_ekindata_t *ekind, real dt,
                        double xi[], double vxi[], t_extmass *MassQ);
 
-t_state *init_bufstate(const t_state *template_state);
-
-void destroy_bufstate(t_state *state);
-
 void trotter_update(t_inputrec *ir, gmx_int64_t step, gmx_ekindata_t *ekind,
                     gmx_enerdata_t *enerd, t_state *state, tensor vir, t_mdatoms *md,
                     t_extmass *MassQ, int **trotter_seqlist, int trotter_seqno);
 
 int **init_npt_vars(t_inputrec *ir, t_state *state, t_extmass *Mass, gmx_bool bTrotter);
 
-real NPT_energy(t_inputrec *ir, t_state *state, t_extmass *MassQ);
+real NPT_energy(const t_inputrec *ir, const t_state *state, const t_extmass *MassQ);
 /* computes all the pressure/tempertature control energy terms to get a conserved energy */
 
 void NBaroT_trotter(t_grpopts *opts, real dt,
@@ -204,9 +206,6 @@ void vrescale_tcoupl(t_inputrec *ir, gmx_int64_t step,
                      double therm_integral[]);
 /* Compute temperature scaling. For V-rescale it is done in update. */
 
-real vrescale_energy(t_grpopts *opts, double therm_integral[]);
-/* Returns the V-rescale contribution to the conserved energy */
-
 void rescale_velocities(gmx_ekindata_t *ekind, t_mdatoms *mdatoms,
                         int start, int end, rvec v[]);
 /* Rescale the velocities with the scaling factor in ekind */
@@ -224,20 +223,21 @@ real calc_pres(int ePBC, int nwall, matrix box, tensor ekin, tensor vir,
  */
 
 void parrinellorahman_pcoupl(FILE *fplog, gmx_int64_t step,
-                             t_inputrec *ir, real dt, tensor pres,
+                             const t_inputrec *ir, real dt, const tensor pres,
                              tensor box, tensor box_rel, tensor boxv,
                              tensor M, matrix mu,
                              gmx_bool bFirstStep);
 
 void berendsen_pcoupl(FILE *fplog, gmx_int64_t step,
-                      t_inputrec *ir, real dt, tensor pres, matrix box,
+                      const t_inputrec *ir, real dt,
+                      const tensor pres, const matrix box,
                       matrix mu);
 
 
-void berendsen_pscale(t_inputrec *ir, matrix mu,
+void berendsen_pscale(const t_inputrec *ir, const matrix mu,
                       matrix box, matrix box_rel,
                       int start, int nr_atoms,
-                      rvec x[], unsigned short cFREEZE[],
+                      rvec x[], const unsigned short cFREEZE[],
                       t_nrnb *nrnb);
 
 void correct_ekin(FILE *log, int start, int end, rvec v[],
index 8f00f22207fcbc5d620b9c3d4e8c7e8557c46f06..a6ecc782efceb9aa93f4673e2c915b23ef4e6629 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2015, by the GROMACS development team, led by
+# Copyright (c) 2015,2016, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
 # To help us fund GROMACS development, we humbly ask that you cite
 # the research papers on the package. Check out http://www.gromacs.org.
 
-file(GLOB MDRUNUTILITY_SOURCES *.cpp)
-set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${MDRUNUTILITY_SOURCES} PARENT_SCOPE)
+gmx_add_libgromacs_sources(
+    handlerestart.cpp
+    mdmodules.cpp
+    threadaffinity.cpp
+    )
 
 if (BUILD_TESTING)
-#    add_subdirectory(tests)
+    add_subdirectory(tests)
 endif()
diff --git a/src/gromacs/mdrunutility/mdmodules.cpp b/src/gromacs/mdrunutility/mdmodules.cpp
new file mode 100644 (file)
index 0000000..6440dd8
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+#include "gmxpre.h"
+
+#include "mdmodules.h"
+
+#include "gromacs/applied-forces/electricfield.h"
+#include "gromacs/mdtypes/inputrec.h"
+#include "gromacs/utility/smalloc.h"
+
+namespace gmx
+{
+
+class MDModules::Impl
+{
+    public:
+        Impl() : ir_(nullptr)
+        {
+        }
+        ~Impl()
+        {
+            if (ir_ != nullptr)
+            {
+                done_inputrec(ir_);
+                sfree(ir_);
+            }
+        }
+
+        void ensureInputrecInitialized()
+        {
+            if (ir_ == nullptr)
+            {
+                field_ = createElectricFieldModule();
+                snew(ir_, 1);
+                snew(ir_->fepvals, 1);
+                snew(ir_->expandedvals, 1);
+                snew(ir_->simtempvals, 1);
+                ir_->efield = field_.get();
+            }
+        }
+
+        std::unique_ptr<IInputRecExtension>  field_;
+        t_inputrec                          *ir_;
+};
+
+MDModules::MDModules() : impl_(new Impl)
+{
+}
+
+MDModules::~MDModules()
+{
+}
+
+t_inputrec *MDModules::inputrec()
+{
+    impl_->ensureInputrecInitialized();
+    return impl_->ir_;
+}
+
+} // namespace gmx
diff --git a/src/gromacs/mdrunutility/mdmodules.h b/src/gromacs/mdrunutility/mdmodules.h
new file mode 100644 (file)
index 0000000..d43cc96
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares gmx::MDModules.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_mdrunutility
+ */
+#ifndef GMX_MDRUNUTILITY_MDMODULES_H
+#define GMX_MDRUNUTILITY_MDMODULES_H
+
+#include "gromacs/utility/classhelpers.h"
+
+struct t_inputrec;
+
+namespace gmx
+{
+
+/*! \libinternal \brief
+ * Factory for t_inputrec.
+ *
+ * This class acts as a central place for constructing t_inputrec (and possibly
+ * other mdrun structures in the future) and wiring up dependencies between
+ * modules that are referenced from these structures.  This class owns all such
+ * modules, and needs to remain in existence as long as the returned data
+ * structures are in use.  Ideally, it is also the only place that creates
+ * instances of these modules (outside test code).
+ *
+ * The general idea is that each module takes care of its own data rather than
+ * mdrun having to know about all the details of each type of force calculation.
+ * Initially this is applied for simple things like electric field calculations
+ * but later more complex forces will be supported too.
+ *
+ * The current approach uses t_inputrec and IInputRecExtension to pass
+ * references to the modules to other code to avoid changing many function
+ * signatures.  Also, the current usage means that nearly every use of
+ * t_inputrec (in particular, reading it from mdp or tpr files) needs to be
+ * initialized through MDModules for correct functionality.  For the future, a
+ * better approach would be to pass around a reference to MDModules instead and
+ * call it directly for cases that are not related to t_inputrec functionality.
+ * This (and other refactoring) would allow simplifying IInputRecExtension.
+ * IForceProvider is the other interface currently used to interact with these
+ * modules.  Also, all the places where these interfaces are used should become
+ * loops over a container of these interfaces, instead of the current single
+ * pointer.
+ *
+ * \inlibraryapi
+ * \ingroup module_mdrunutility
+ */
+class MDModules
+{
+    public:
+        MDModules();
+        ~MDModules();
+
+        /*! \brief
+         * Returns an initialized t_inputrec structure.
+         *
+         * The inputrec structure is owned by MDModules and will be destroyed
+         * with it.
+         */
+        t_inputrec *inputrec();
+
+    private:
+        class Impl;
+
+        PrivateImplPointer<Impl> impl_;
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/mdrunutility/tests/CMakeLists.txt b/src/gromacs/mdrunutility/tests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7ccbbd9
--- /dev/null
@@ -0,0 +1,40 @@
+#
+# This file is part of the GROMACS molecular simulation package.
+#
+# Copyright (c) 2016, by the GROMACS development team, led by
+# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+# and including many others, as listed in the AUTHORS file in the
+# top-level source directory and at http://www.gromacs.org.
+#
+# GROMACS is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1
+# of the License, or (at your option) any later version.
+#
+# GROMACS is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with GROMACS; if not, see
+# http://www.gnu.org/licenses, or write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+#
+# If you want to redistribute modifications to GROMACS, please
+# consider that scientific software is very special. Version
+# control is crucial - bugs must be traceable. We will be happy to
+# consider code for inclusion in the official distribution, but
+# derived work must not be called official GROMACS. Details are found
+# in the README & COPYING files - if they are missing, get the
+# official version at http://www.gromacs.org.
+#
+# To help us fund GROMACS development, we humbly ask that you cite
+# the research papers on the package. Check out http://www.gromacs.org.
+
+gmx_add_unit_test_object_library(mdrunutility-test-shared
+                                 threadaffinitytest.cpp)
+
+gmx_add_unit_test(MdrunUtilityUnitTests mdrunutility-test
+                  threadaffinity.cpp
+                  $<TARGET_OBJECTS:mdrunutility-test-shared>)
diff --git a/src/gromacs/mdrunutility/tests/threadaffinity.cpp b/src/gromacs/mdrunutility/tests/threadaffinity.cpp
new file mode 100644 (file)
index 0000000..6d11834
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+#include "gmxpre.h"
+
+#include "gromacs/mdrunutility/threadaffinity.h"
+
+#include "config.h"
+
+#include <gtest/gtest.h>
+
+#include "threadaffinitytest.h"
+
+namespace
+{
+
+class ThreadAffinityTest : public ::testing::Test
+{
+    public:
+        gmx::test::ThreadAffinityTestHelper helper_;
+};
+
+TEST_F(ThreadAffinityTest, DoesNothingWhenDisabled)
+{
+    helper_.setAffinityOption(threadaffOFF);
+    helper_.setAffinity(1);
+}
+
+TEST_F(ThreadAffinityTest, DoesNothingWhenNotSupported)
+{
+    helper_.setAffinitySupported(false);
+    helper_.setAffinity(1);
+}
+
+TEST_F(ThreadAffinityTest, DoesNothingWithAutoAndTooFewThreads)
+{
+    helper_.setLogicalProcessorCount(4);
+    helper_.setAffinity(2);
+}
+
+TEST_F(ThreadAffinityTest, DoesNothingWithAutoAndTooManyThreads)
+{
+    helper_.setLogicalProcessorCount(4);
+    helper_.setAffinity(8);
+}
+
+TEST_F(ThreadAffinityTest, DoesNothingWithUnknownHardware)
+{
+    helper_.setAffinityOption(threadaffON);
+    helper_.setLogicalProcessorCount(0);
+    helper_.setAffinity(2);
+}
+
+TEST_F(ThreadAffinityTest, DoesNothingWithTooManyThreads)
+{
+    helper_.setAffinityOption(threadaffON);
+    helper_.setLogicalProcessorCount(4);
+    helper_.setAffinity(8);
+}
+
+TEST_F(ThreadAffinityTest, DoesNothingWithTooLargeOffset)
+{
+    helper_.setAffinityOption(threadaffON);
+    helper_.setOffsetAndStride(2, 0);
+    helper_.setLogicalProcessorCount(4);
+    helper_.setAffinity(3);
+}
+
+TEST_F(ThreadAffinityTest, DoesNothingWithTooLargeStride)
+{
+    helper_.setAffinityOption(threadaffON);
+    helper_.setOffsetAndStride(0, 2);
+    helper_.setLogicalProcessorCount(4);
+    helper_.setAffinity(3);
+}
+
+TEST_F(ThreadAffinityTest, PinsSingleThreadWithAuto)
+{
+    helper_.setLogicalProcessorCount(1);
+    helper_.expectAffinitySet(0);
+    helper_.setAffinity(1);
+}
+
+TEST_F(ThreadAffinityTest, PinsSingleThreadWhenForced)
+{
+    helper_.setAffinityOption(threadaffON);
+    helper_.setLogicalProcessorCount(2);
+    helper_.expectAffinitySet(0);
+    helper_.setAffinity(1);
+}
+
+TEST_F(ThreadAffinityTest, PinsSingleThreadWithOffsetWhenForced)
+{
+    helper_.setAffinityOption(threadaffON);
+    helper_.setOffsetAndStride(2, 0);
+    helper_.setLogicalProcessorCount(4);
+    helper_.expectAffinitySet(2);
+    helper_.setAffinity(1);
+}
+
+TEST_F(ThreadAffinityTest, HandlesPinningFailureWithSingleThread)
+{
+    helper_.setLogicalProcessorCount(1);
+    helper_.expectAffinitySetThatFails(0);
+    helper_.setAffinity(1);
+}
+
+// TODO: If it wouldn't result in a multitude of #if's, it would be nice
+// to somehow indicate in a no-OpenMP build that some tests are missing.
+#if GMX_OPENMP
+TEST_F(ThreadAffinityTest, PinsMultipleThreadsWithAuto)
+{
+    helper_.setLogicalProcessorCount(2);
+    helper_.expectAffinitySet({0, 1});
+    helper_.setAffinity(2);
+}
+
+TEST_F(ThreadAffinityTest, PinsMultipleThreadsWithStrideWhenForced)
+{
+    helper_.setAffinityOption(threadaffON);
+    helper_.setOffsetAndStride(0, 2);
+    helper_.setLogicalProcessorCount(4);
+    helper_.expectAffinitySet({0, 2});
+    helper_.setAffinity(2);
+}
+
+TEST_F(ThreadAffinityTest, HandlesPinningFailureWithOneThreadFailing)
+{
+    helper_.setAffinityOption(threadaffON);
+    helper_.setLogicalProcessorCount(2);
+    helper_.expectAffinitySet(0);
+    helper_.expectAffinitySetThatFails(1);
+    helper_.setAffinity(2);
+}
+#endif
+
+} // namespace
diff --git a/src/gromacs/mdrunutility/tests/threadaffinitytest.cpp b/src/gromacs/mdrunutility/tests/threadaffinitytest.cpp
new file mode 100644 (file)
index 0000000..33824ce
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+#include "gmxpre.h"
+
+#include "threadaffinitytest.h"
+
+#include "config.h"
+
+#include <gmock/gmock.h>
+
+#include "gromacs/hardware/hardwaretopology.h"
+#include "gromacs/mdtypes/commrec.h"
+#include "gromacs/utility/basenetwork.h"
+#include "gromacs/utility/gmxmpi.h"
+#include "gromacs/utility/smalloc.h"
+
+namespace gmx
+{
+namespace test
+{
+
+MockThreadAffinityAccess::MockThreadAffinityAccess()
+    : supported_(true)
+{
+    using ::testing::_;
+    using ::testing::Return;
+    ON_CALL(*this, setCurrentThreadAffinityToCore(_))
+        .WillByDefault(Return(true));
+}
+
+MockThreadAffinityAccess::~MockThreadAffinityAccess()
+{
+}
+
+
+ThreadAffinityTestHelper::ThreadAffinityTestHelper()
+{
+    snew(cr_, 1);
+    cr_->nnodes         = gmx_node_num();
+    cr_->nodeid         = gmx_node_rank();
+    cr_->rank_intranode = cr_->nodeid;
+    cr_->duty           = DUTY_PP;
+#if GMX_MPI
+    cr_->mpi_comm_mysim = MPI_COMM_WORLD;
+#endif
+    snew(hwOpt_, 1);
+    hwOpt_->thread_affinity = threadaffAUTO;
+}
+
+ThreadAffinityTestHelper::~ThreadAffinityTestHelper()
+{
+    sfree(cr_);
+    sfree(hwOpt_);
+}
+
+void ThreadAffinityTestHelper::setLogicalProcessorCount(int logicalProcessorCount)
+{
+    hwTop_.reset(new HardwareTopology(logicalProcessorCount));
+}
+
+} // namespace test
+} // namespace gmx
diff --git a/src/gromacs/mdrunutility/tests/threadaffinitytest.h b/src/gromacs/mdrunutility/tests/threadaffinitytest.h
new file mode 100644 (file)
index 0000000..027e6cf
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+#ifndef GMX_MDRUNUTILITY_TESTS_THREADAFFINITYTEST_H
+#define GMX_MDRUNUTILITY_TESTS_THREADAFFINITYTEST_H
+
+#include <initializer_list>
+#include <memory>
+
+#include <gmock/gmock.h>
+
+#include "gromacs/hardware/hw_info.h"
+#include "gromacs/mdrunutility/threadaffinity.h"
+#include "gromacs/utility/logger.h"
+
+struct t_commrec;
+
+namespace gmx
+{
+
+class HardwareTopology;
+
+namespace test
+{
+
+class MockThreadAffinityAccess : public IThreadAffinityAccess
+{
+    public:
+        MockThreadAffinityAccess();
+        ~MockThreadAffinityAccess();
+
+        void setSupported(bool supported) { supported_ = supported; }
+
+        virtual bool isThreadAffinitySupported() const { return supported_; }
+        MOCK_METHOD1(setCurrentThreadAffinityToCore, bool(int core));
+
+    private:
+        bool supported_;
+};
+
+class ThreadAffinityTestHelper
+{
+    public:
+        ThreadAffinityTestHelper();
+        ~ThreadAffinityTestHelper();
+
+        void setAffinitySupported(bool supported)
+        {
+            affinityAccess_.setSupported(supported);
+        }
+        void setAffinityOption(int affinityOption)
+        {
+            hwOpt_->thread_affinity = affinityOption;
+        }
+        void setOffsetAndStride(int offset, int stride)
+        {
+            hwOpt_->core_pinning_offset = offset;
+            hwOpt_->core_pinning_stride = stride;
+        }
+
+        void setLogicalProcessorCount(int logicalProcessorCount);
+
+        void expectAffinitySet(int core)
+        {
+            EXPECT_CALL(affinityAccess_, setCurrentThreadAffinityToCore(core));
+        }
+        void expectAffinitySet(std::initializer_list<int> cores)
+        {
+            for (int core : cores)
+            {
+                expectAffinitySet(core);
+            }
+        }
+        void expectAffinitySetThatFails(int core)
+        {
+            using ::testing::Return;
+            EXPECT_CALL(affinityAccess_, setCurrentThreadAffinityToCore(core))
+                .WillOnce(Return(false));
+        }
+
+        void setAffinity(int nthread_local)
+        {
+            if (hwTop_ == nullptr)
+            {
+                setLogicalProcessorCount(1);
+            }
+            MDLogger mdlog;
+            gmx_set_thread_affinity(nullptr, mdlog, cr_, hwOpt_, *hwTop_,
+                                    nthread_local, &affinityAccess_);
+        }
+
+    private:
+        t_commrec                         *cr_;
+        gmx_hw_opt_t                      *hwOpt_;
+        std::unique_ptr<HardwareTopology>  hwTop_;
+        MockThreadAffinityAccess           affinityAccess_;
+};
+
+} // namespace test
+} // namespace gmx
+
+#endif
index a9387e6b3543d32c95d5f063e03fdaeef404fc13..d30e078a74833d64e9e8a0a5b1ace8ab0f8857a1 100644 (file)
 
 #include "thread_mpi/threads.h"
 
-#include "gromacs/gmxlib/md_logging.h"
 #include "gromacs/hardware/hardwaretopology.h"
 #include "gromacs/hardware/hw_info.h"
-#include "gromacs/mdlib/gmx_omp_nthreads.h"
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/utility/basenetwork.h"
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/gmxomp.h"
+#include "gromacs/utility/logger.h"
 #include "gromacs/utility/programcontext.h"
 #include "gromacs/utility/scoped_cptr.h"
 #include "gromacs/utility/smalloc.h"
 
+namespace
+{
+
+class DefaultThreadAffinityAccess : public gmx::IThreadAffinityAccess
+{
+    public:
+        virtual bool isThreadAffinitySupported() const
+        {
+            return tMPI_Thread_setaffinity_support() == TMPI_SETAFFINITY_SUPPORT_YES;
+        }
+        virtual bool setCurrentThreadAffinityToCore(int core)
+        {
+            const int ret = tMPI_Thread_setaffinity_single(tMPI_Thread_self(), core);
+            return ret == 0;
+        }
+};
+
+//! Global instance of DefaultThreadAffinityAccess
+DefaultThreadAffinityAccess g_defaultAffinityAccess;
+
+} // namespace
+
+gmx::IThreadAffinityAccess::~IThreadAffinityAccess()
+{
+}
 
 static bool invalidWithinSimulation(const t_commrec *cr, bool invalidLocally)
 {
@@ -83,9 +107,9 @@ static bool invalidWithinSimulation(const t_commrec *cr, bool invalidLocally)
 }
 
 static bool
-get_thread_affinity_layout(FILE *fplog,
+get_thread_affinity_layout(FILE *fplog, const gmx::MDLogger &mdlog,
                            const t_commrec *cr,
-                           const gmx_hw_info_t * hwinfo,
+                           const gmx::HardwareTopology &hwTop,
                            int   threads,
                            bool  automatic,
                            int pin_offset, int * pin_stride,
@@ -97,8 +121,6 @@ get_thread_affinity_layout(FILE *fplog,
     bool                         haveTopology;
     bool                         invalidValue;
 
-    const gmx::HardwareTopology &hwTop = *hwinfo->hardwareTopology;
-
     haveTopology = (hwTop.supportLevel() >= gmx::HardwareTopology::SupportLevel::Basic);
 
     if (pin_offset < 0)
@@ -131,7 +153,7 @@ get_thread_affinity_layout(FILE *fplog,
     else
     {
         /* topology information not available or invalid, ignore it */
-        hwThreads       = hwinfo->nthreads_hw_avail;
+        hwThreads       = hwTop.machine().logicalProcessorCount;
         *localityOrder  = NULL;
     }
     // Only warn about the first problem per node.  Otherwise, the first test
@@ -144,8 +166,8 @@ get_thread_affinity_layout(FILE *fplog,
     if (invalidWithinSimulation(cr, invalidValue))
     {
         /* We don't know anything about the hardware, don't pin */
-        md_print_warn(cr, fplog,
-                      "NOTE: No information on available cores, thread pinning disabled.\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText(
+                "NOTE: No information on available cores, thread pinning disabled.");
         alreadyWarned = true;
     }
     bool validLayout = !invalidValue;
@@ -156,11 +178,11 @@ get_thread_affinity_layout(FILE *fplog,
         bool warn = (invalidValue && threads > 1 && threads < hwThreads);
         if (invalidWithinSimulation(cr, warn) && !alreadyWarned)
         {
-            md_print_warn(cr, fplog,
-                          "NOTE: The number of threads is not equal to the number of (logical) cores\n"
-                          "      and the -pin option is set to auto: will not pin thread to cores.\n"
-                          "      This can lead to significant performance degradation.\n"
-                          "      Consider using -pin on (and -pinoffset in case you run multiple jobs).\n");
+            GMX_LOG(mdlog.warning).asParagraph().appendText(
+                    "NOTE: The number of threads is not equal to the number of (logical) cores\n"
+                    "      and the -pin option is set to auto: will not pin thread to cores.\n"
+                    "      This can lead to significant performance degradation.\n"
+                    "      Consider using -pin on (and -pinoffset in case you run multiple jobs).");
             alreadyWarned = true;
         }
         validLayout = validLayout && !invalidValue;
@@ -169,8 +191,8 @@ get_thread_affinity_layout(FILE *fplog,
     invalidValue = (threads > hwThreads);
     if (invalidWithinSimulation(cr, invalidValue) && !alreadyWarned)
     {
-        md_print_warn(cr, fplog,
-                      "NOTE: Oversubscribing a CPU, will not pin threads.\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText(
+                "NOTE: Oversubscribing the CPU, will not pin threads");
         alreadyWarned = true;
     }
     validLayout = validLayout && !invalidValue;
@@ -178,8 +200,8 @@ get_thread_affinity_layout(FILE *fplog,
     invalidValue = (pin_offset + threads > hwThreads);
     if (invalidWithinSimulation(cr, invalidValue) && !alreadyWarned)
     {
-        md_print_warn(cr, fplog,
-                      "WARNING: Requested offset too large for available cores, thread pinning disabled.\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText(
+                "WARNING: Requested offset too large for available cores, thread pinning disabled.");
         alreadyWarned = true;
 
     }
@@ -219,8 +241,8 @@ get_thread_affinity_layout(FILE *fplog,
     if (invalidWithinSimulation(cr, invalidValue) && !alreadyWarned)
     {
         /* We are oversubscribing, don't pin */
-        md_print_warn(cr, fplog,
-                      "WARNING: Requested stride too large for available cores, thread pinning disabled.\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText(
+                "WARNING: Requested stride too large for available cores, thread pinning disabled.");
     }
     validLayout = validLayout && !invalidValue;
 
@@ -235,7 +257,8 @@ get_thread_affinity_layout(FILE *fplog,
 }
 
 static bool set_affinity(const t_commrec *cr, int nthread_local, int thread0_id_node,
-                         int offset, int core_pinning_stride, int *localityOrder)
+                         int offset, int core_pinning_stride, int *localityOrder,
+                         gmx::IThreadAffinityAccess *affinityAccess)
 {
     // Set the per-thread affinity. In order to be able to check the success
     // of affinity settings, we will set nth_affinity_set to 1 on threads
@@ -253,7 +276,6 @@ static bool set_affinity(const t_commrec *cr, int nthread_local, int thread0_id_
         {
             int      thread_id, thread_id_node;
             int      index, core;
-            gmx_bool setaffinity_ret;
 
             thread_id      = gmx_omp_get_thread_num();
             thread_id_node = thread0_id_node + thread_id;
@@ -267,15 +289,15 @@ static bool set_affinity(const t_commrec *cr, int nthread_local, int thread0_id_
                 core = index;
             }
 
-            setaffinity_ret = tMPI_Thread_setaffinity_single(tMPI_Thread_self(), core);
+            const bool ret = affinityAccess->setCurrentThreadAffinityToCore(core);
 
             /* store the per-thread success-values of the setaffinity */
-            nth_affinity_set += (setaffinity_ret == 0);
+            nth_affinity_set += (ret ? 1 : 0);
 
             if (debug)
             {
                 fprintf(debug, "On rank %2d, thread %2d, index %2d, core %2d the affinity setting returned %d\n",
-                        cr->nodeid, gmx_omp_get_thread_num(), index, core, setaffinity_ret);
+                        cr->nodeid, gmx_omp_get_thread_num(), index, core, ret ? 1 : 0);
             }
         }
         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
@@ -332,13 +354,15 @@ static bool set_affinity(const t_commrec *cr, int nthread_local, int thread0_id_
    if only PME is using threads.
  */
 void
-gmx_set_thread_affinity(FILE                *fplog,
-                        const t_commrec     *cr,
-                        const gmx_hw_opt_t  *hw_opt,
-                        const gmx_hw_info_t *hwinfo)
+gmx_set_thread_affinity(FILE                        *fplog,
+                        const gmx::MDLogger         &mdlog,
+                        const t_commrec             *cr,
+                        const gmx_hw_opt_t          *hw_opt,
+                        const gmx::HardwareTopology &hwTop,
+                        int                          nthread_local,
+                        gmx::IThreadAffinityAccess  *affinityAccess)
 {
-    int        thread0_id_node,
-               nthread_local, nthread_node;
+    int        thread0_id_node, nthread_node;
     int *      localityOrder = nullptr;
 
     if (hw_opt->thread_affinity == threadaffOFF)
@@ -347,31 +371,26 @@ gmx_set_thread_affinity(FILE                *fplog,
         return;
     }
 
+    if (affinityAccess == nullptr)
+    {
+        affinityAccess = &g_defaultAffinityAccess;
+    }
+
     /* If the tMPI thread affinity setting is not supported encourage the user
      * to report it as it's either a bug or an exotic platform which we might
      * want to support. */
-    if (tMPI_Thread_setaffinity_support() != TMPI_SETAFFINITY_SUPPORT_YES)
+    if (!affinityAccess->isThreadAffinitySupported())
     {
         /* we know Mac OS & BlueGene do not support setting thread affinity, so there's
            no point in warning the user in that case. In any other case
            the user might be able to do something about it. */
 #if !defined(__APPLE__) && !defined(__bg__)
-        md_print_warn(cr, fplog,
-                      "NOTE: Cannot set thread affinities on the current platform.\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText(
+                "NOTE: Cannot set thread affinities on the current platform.");
 #endif  /* __APPLE__ */
         return;
     }
 
-    /* threads on this MPI process or TMPI thread */
-    if (cr->duty & DUTY_PP)
-    {
-        nthread_local = gmx_omp_nthreads_get(emntNonbonded);
-    }
-    else
-    {
-        nthread_local = gmx_omp_nthreads_get(emntPME);
-    }
-
     /* map the current process to cores */
     thread0_id_node = 0;
     nthread_node    = nthread_local;
@@ -399,12 +418,12 @@ gmx_set_thread_affinity(FILE                *fplog,
     int  core_pinning_stride = hw_opt->core_pinning_stride;
     if (offset != 0)
     {
-        md_print_info(cr, fplog, "Applying core pinning offset %d\n", offset);
+        GMX_LOG(mdlog.warning).appendTextFormatted("Applying core pinning offset %d", offset);
     }
 
     bool automatic = (hw_opt->thread_affinity == threadaffAUTO);
     bool validLayout
-        = get_thread_affinity_layout(fplog, cr, hwinfo, nthread_node, automatic,
+        = get_thread_affinity_layout(fplog, mdlog, cr, hwTop, nthread_node, automatic,
                                      offset, &core_pinning_stride, &localityOrder);
     gmx::scoped_guard_sfree localityOrderGuard(localityOrder);
 
@@ -412,7 +431,8 @@ gmx_set_thread_affinity(FILE                *fplog,
     if (validLayout)
     {
         allAffinitiesSet = set_affinity(cr, nthread_local, thread0_id_node,
-                                        offset, core_pinning_stride, localityOrder);
+                                        offset, core_pinning_stride, localityOrder,
+                                        affinityAccess);
     }
     else
     {
@@ -421,9 +441,9 @@ gmx_set_thread_affinity(FILE                *fplog,
     }
     if (invalidWithinSimulation(cr, !allAffinitiesSet))
     {
-        md_print_warn(cr, fplog,
-                      "NOTE: Thread affinity setting failed. This can cause performance degradation.\n"
-                      "      If you think your settings are correct, ask on the gmx-users list.\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText(
+                "NOTE: Thread affinity setting failed. This can cause performance degradation.\n"
+                "      If you think your settings are correct, ask on the gmx-users list.");
     }
 }
 
@@ -432,11 +452,11 @@ gmx_set_thread_affinity(FILE                *fplog,
  * Note that this will only work on Linux as we use a GNU feature.
  */
 void
-gmx_check_thread_affinity_set(FILE            *fplog,
-                              const t_commrec *cr,
-                              gmx_hw_opt_t    *hw_opt,
-                              int  gmx_unused  nthreads_hw_avail,
-                              gmx_bool         bAfterOpenmpInit)
+gmx_check_thread_affinity_set(const gmx::MDLogger &mdlog,
+                              const t_commrec     *cr,
+                              gmx_hw_opt_t        *hw_opt,
+                              int  gmx_unused      nthreads_hw_avail,
+                              gmx_bool             bAfterOpenmpInit)
 {
     GMX_RELEASE_ASSERT(hw_opt, "hw_opt must be a non-NULL pointer");
 
@@ -453,7 +473,7 @@ gmx_check_thread_affinity_set(FILE            *fplog,
             if (!gmx_omp_check_thread_affinity(&message))
             {
                 /* TODO: with -pin auto we should only warn when using all cores */
-                md_print_warn(cr, fplog, "%s", message);
+                GMX_LOG(mdlog.warning).asParagraph().appendText(message);
                 sfree(message);
                 hw_opt->thread_affinity = threadaffOFF;
             }
@@ -537,14 +557,14 @@ gmx_check_thread_affinity_set(FILE            *fplog,
         {
             if (!bAfterOpenmpInit)
             {
-                md_print_warn(cr, fplog,
-                              "Non-default thread affinity set, disabling internal thread affinity");
+                GMX_LOG(mdlog.warning).asParagraph().appendText(
+                        "Non-default thread affinity set, disabling internal thread affinity");
             }
             else
             {
-                md_print_warn(cr, fplog,
-                              "Non-default thread affinity set probably by the OpenMP library,\n"
-                              "disabling internal thread affinity");
+                GMX_LOG(mdlog.warning).asParagraph().appendText(
+                        "Non-default thread affinity set probably by the OpenMP library,\n"
+                        "disabling internal thread affinity");
             }
             hw_opt->thread_affinity = threadaffOFF;
         }
@@ -553,9 +573,9 @@ gmx_check_thread_affinity_set(FILE            *fplog,
             /* Only warn once, at the last check (bAfterOpenmpInit==TRUE) */
             if (bAfterOpenmpInit)
             {
-                md_print_warn(cr, fplog,
-                              "Overriding thread affinity set outside %s\n",
-                              gmx::getProgramContext().displayName());
+                GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                        "Overriding thread affinity set outside %s",
+                        gmx::getProgramContext().displayName());
             }
         }
 
index 8ca8854bf2d35f08c4b5e939a3cc2e98d0394c7b..28c7acddafb821237a99ebff51adb9080516d444 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 
 #include <cstdio>
 
-#include "gromacs/hardware/hw_info.h"
 #include "gromacs/utility/basedefinitions.h"
 
+struct gmx_hw_opt_t;
 struct t_commrec;
 
+namespace gmx
+{
+
+class HardwareTopology;
+class MDLogger;
+
+class IThreadAffinityAccess
+{
+    public:
+        virtual bool isThreadAffinitySupported() const        = 0;
+        virtual bool setCurrentThreadAffinityToCore(int core) = 0;
+
+    protected:
+        virtual ~IThreadAffinityAccess();
+};
+
+} // namespace gmx
+
 /*! \brief
  * Sets the thread affinity using the requested setting stored in hw_opt.
- *
- * The hardware topology is requested from hwinfo, when present.
  */
 void
-gmx_set_thread_affinity(FILE                *fplog,
-                        const t_commrec     *cr,
-                        const gmx_hw_opt_t  *hw_opt,
-                        const gmx_hw_info_t *hwinfo);
+gmx_set_thread_affinity(FILE                        *fplog,
+                        const gmx::MDLogger         &mdlog,
+                        const t_commrec             *cr,
+                        const gmx_hw_opt_t          *hw_opt,
+                        const gmx::HardwareTopology &hwTop,
+                        int                          nthread_local,
+                        gmx::IThreadAffinityAccess  *affinityAccess);
 
 /*! \brief
  * Checks the process affinity mask and if it is found to be non-zero,
@@ -75,7 +94,7 @@ gmx_set_thread_affinity(FILE                *fplog,
  * variables for setting the affinity are set.
  */
 void
-gmx_check_thread_affinity_set(FILE *fplog, const t_commrec *cr,
+gmx_check_thread_affinity_set(const gmx::MDLogger &mdlog, const t_commrec *cr,
                               gmx_hw_opt_t *hw_opt, int ncpus,
                               gmx_bool bAfterOpenmpInit);
 
index cbdb1a9fe43e685fe4dbf49840183f3c56cfdd65..910ea36e8d21bc3183cb00857d581c036a51e1ad 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  * To help us fund GROMACS development, we humbly ask that you cite
  * the research papers on the package. Check out http://www.gromacs.org.
  */
+
+/*! \libinternal \file
+ *
+ *
+ * \brief
+ * This file contains datatypes for energy statistics history.
+ *
+ * \author Berk Hess
+ *
+ * \inlibraryapi
+ * \ingroup module_mdtypes
+ */
+
 #ifndef GMX_MDLIB_ENERGYHISTORY_H
 #define GMX_MDLIB_ENERGYHISTORY_H
 
+#include <memory>
+#include <vector>
+
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 
-/* energy history for delta_h histograms */
-typedef struct delta_h_history_t
-{
-    int      nndh;             /* the number of energy difference lists */
-    int     *ndh;              /* the number in each energy difference list */
-    real   **dh;               /* the energy difference lists */
+//! \cond INTERNAL
 
-    double   start_time;       /* the start time of these energy diff blocks */
-    double   start_lambda;     /* lambda at start time */
+//! \brief Energy history for delta_h histograms in between energy file frames
+class delta_h_history_t
+{
+    public:
+        //! Vector (size number of intermediate data points) of vector of Hamiltonian differences for each foreign lambda
+        std::vector<std::vector<real> > dh;
+        //! The start time of these energy diff blocks
+        double                          start_time;
+        //! Lambda at start time
+        double                          start_lambda;
+        //! Whether the lambda value is set. Here for backward-compatibility.
+        gmx_bool                        start_lambda_set;
 
-    gmx_bool start_lambda_set; /* whether the lambda value is set. Here
-                                  For backward-compatibility. */
-} delta_h_history_t;
+        //! Constructor
+        delta_h_history_t() : dh(),
+                              start_time(0),
+                              start_lambda(0),
+                              start_lambda_set(false)
+        {
+        }
+};
 
 
-typedef struct energyhistory_t
+//! \brief Energy statistics history, only used for output and reporting
+class energyhistory_t
 {
-    gmx_int64_t        nsteps;       /* The number of steps in the history            */
-    gmx_int64_t        nsum;         /* The nr. of steps in the ener_ave and ener_sum */
-    double         *   ener_ave;     /* Energy term history sum to get fluctuations   */
-    double         *   ener_sum;     /* Energy term history sum to get fluctuations   */
-    int                nener;        /* Number of energy terms in two previous arrays */
-    gmx_int64_t        nsteps_sim;   /* The number of steps in ener_sum_sim      */
-    gmx_int64_t        nsum_sim;     /* The number of frames in ener_sum_sim     */
-    double         *   ener_sum_sim; /* Energy term history sum of the whole sim      */
+    public:
+        gmx_int64_t         nsteps;       //! The number of steps in the history
+        gmx_int64_t         nsum;         //! Nr. of steps in the ener_ave and ener_sum
+        std::vector<double> ener_ave;     //! Energy terms difference^2 sum to get fluctuations
+        std::vector<double> ener_sum;     //! Energy terms sum
+        gmx_int64_t         nsteps_sim;   //! The number of steps in ener_sum_sim
+        gmx_int64_t         nsum_sim;     //! The number of frames in ener_sum_sim
+        std::vector<double> ener_sum_sim; //! Energy term history sum of the whole sim
 
-    delta_h_history_t *dht;          /* The BAR energy differences */
-}
-energyhistory_t;
+        //! History for energy difference for foreign lambdas (useful for BAR)
+        std::unique_ptr<delta_h_history_t> deltaHForeignLambdas;
 
-/* \brief Initialize an energy history structure
- */
-void init_energyhistory(energyhistory_t * enerhist);
+        //! Constructor
+        energyhistory_t() : nsteps(0),
+                            nsum(0),
+                            ener_ave(),
+                            ener_sum(),
+                            nsteps_sim(0),
+                            nsum_sim(0),
+                            ener_sum_sim(0)
+        {
+        }
+};
 
-/* \brief Destroy an energy history structure
- */
-void done_energyhistory(energyhistory_t * enerhist);
+//! \endcond
 
 #endif
index 1ba04de5238db7940e6865baa5d6a92a2e1851d4..7cabf08377e11c2f7eed9c21137adb6980b7b6ec 100644 (file)
@@ -38,6 +38,9 @@
 #define GMX_MDTYPES_TYPES_FORCEREC_H
 
 #include "gromacs/math/vectypes.h"
+#ifdef __cplusplus
+#include "gromacs/math/paddedvector.h"
+#endif
 #include "gromacs/mdtypes/interaction_const.h"
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/topology/idef.h"
 #include "gromacs/utility/real.h"
 
 #ifdef __cplusplus
+
 extern "C" {
-#endif
-#if 0
-} /* fixes auto-indentation problems */
+
+struct t_mdatoms;
+struct t_commrec;
+
+/*! \libinternal \brief
+ * Interface for a component that provides forces during MD.
+ *
+ * This is typically part of a larger structure/class managing its own
+ * data, such that it has the information on what to do stored locally.
+ * \todo Implement returning of energy and dH/dlambda.
+ * \inlibraryapi
+ */
+struct IForceProvider
+{
+    public:
+        /*! \brief Compute forces
+         *
+         * \todo This is specific for electric fields and needs to be generalized.
+         * \param[in]    cr      Communication record for parallel operations
+         * \param[in]    mdatoms Atom information
+         * \param[inout] force   The forces
+         * \param[in]    t       The actual time in the simulation (ps)
+         */
+        virtual void calculateForces(const t_commrec  *cr,
+                                     const t_mdatoms  *mdatoms,
+                                     PaddedRVecVector *force,
+                                     double            t) = 0;
+
+    protected:
+        ~IForceProvider() {}
+};
 #endif
 
 /* Abstract type for PME that is defined only in the routine that use them. */
@@ -303,15 +335,24 @@ typedef struct t_forcerec {
 
     /* Forces that should not enter into the virial summation:
      * PPPM/PME/Ewald/posres
+     * If such forces are present in the system, bF_NoVirSum=TRUE.
      */
-    gmx_bool bF_NoVirSum;
-    int      f_novirsum_n;
-    int      f_novirsum_nalloc;
-    rvec    *f_novirsum_alloc;
-    /* Pointer that points to f_novirsum_alloc when pressure is calcaluted,
-     * points to the normal force vectors wen pressure is not requested.
+    gmx_bool          bF_NoVirSum;
+#ifdef __cplusplus
+    /* TODO: Replace the pointer by an object once we got rid of C */
+    PaddedRVecVector *forceBufferNoVirialSummation;
+#else
+    void             *forceBufferNoVirialSummation_dummy;
+#endif
+    /* Pointer that points to forceNoVirialSummation when virial is calcaluted,
+     * points to the normal force vector when the virial is not requested
+     * or when bF_NoVirSum == FALSE.
      */
-    rvec *f_novirsum;
+#ifdef __cplusplus
+    PaddedRVecVector *f_novirsum;
+#else
+    void             *f_novirsum_xdummy;
+#endif
 
     /* Long-range forces and virial for PPPM/PME/Ewald */
     struct gmx_pme_t *pmedata;
@@ -421,8 +462,10 @@ typedef struct t_forcerec {
     struct bonded_threading_t *bonded_threading;
 
     /* Ewald correction thread local virial and energy data */
-    int                  nthread_ewc;
-    ewald_corr_thread_t *ewc_t;
+    int                    nthread_ewc;
+    ewald_corr_thread_t   *ewc_t;
+
+    struct IForceProvider *efield;
 } t_forcerec;
 
 /* Important: Starting with Gromacs-4.6, the values of c6 and c12 in the nbfp array have
index 5e6159b633b24317912a89e2e8633473bf7a7586..a10bc47d68ab95c539de1958b8a38c4d541f2066 100644 (file)
 
 #include <algorithm>
 
+#include "gromacs/math/veccompare.h"
 #include "gromacs/math/vecdump.h"
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/mdtypes/pull-params.h"
 #include "gromacs/pbcutil/pbc.h"
+#include "gromacs/utility/compare.h"
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/smalloc.h"
@@ -251,14 +253,6 @@ gmx_bool ir_vdw_might_be_zero_at_cutoff(const t_inputrec *ir)
     return (ir_vdw_is_zero_at_cutoff(ir) || ir->vdwtype == evdwUSER);
 }
 
-void init_inputrec(t_inputrec *ir)
-{
-    std::memset(ir, 0, sizeof(*ir));
-    snew(ir->fepvals, 1);
-    snew(ir->expandedvals, 1);
-    snew(ir->simtempvals, 1);
-}
-
 static void done_pull_group(t_pull_group *pgrp)
 {
     if (pgrp->nat > 0)
@@ -283,28 +277,6 @@ static void done_pull_params(pull_params_t *pull)
 
 void done_inputrec(t_inputrec *ir)
 {
-    int m;
-
-    for (m = 0; (m < DIM); m++)
-    {
-        if (ir->ex[m].a)
-        {
-            sfree(ir->ex[m].a);
-        }
-        if (ir->ex[m].phi)
-        {
-            sfree(ir->ex[m].phi);
-        }
-        if (ir->et[m].a)
-        {
-            sfree(ir->et[m].a);
-        }
-        if (ir->et[m].phi)
-        {
-            sfree(ir->et[m].phi);
-        }
-    }
-
     sfree(ir->opts.nrdf);
     sfree(ir->opts.ref_t);
     sfree(ir->opts.annealing);
@@ -326,6 +298,9 @@ void done_inputrec(t_inputrec *ir)
     sfree(ir->opts.SAsteps);
     sfree(ir->opts.bOPT);
     sfree(ir->opts.bTS);
+    sfree(ir->fepvals);
+    sfree(ir->expandedvals);
+    sfree(ir->simtempvals);
 
     if (ir->pull)
     {
@@ -475,40 +450,6 @@ static void pr_matrix(FILE *fp, int indent, const char *title, const rvec *m,
     }
 }
 
-static void pr_cosine(FILE *fp, int indent, const char *title, const t_cosines *cos,
-                      gmx_bool bMDPformat)
-{
-    int j;
-
-    if (bMDPformat)
-    {
-        fprintf(fp, "%s = %d\n", title, cos->n);
-    }
-    else
-    {
-        indent = pr_title(fp, indent, title);
-        pr_indent(fp, indent);
-        fprintf(fp, "n = %d\n", cos->n);
-        if (cos->n > 0)
-        {
-            pr_indent(fp, indent+2);
-            fprintf(fp, "a =");
-            for (j = 0; (j < cos->n); j++)
-            {
-                fprintf(fp, " %e", cos->a[j]);
-            }
-            fprintf(fp, "\n");
-            pr_indent(fp, indent+2);
-            fprintf(fp, "phi =");
-            for (j = 0; (j < cos->n); j++)
-            {
-                fprintf(fp, " %e", cos->phi[j]);
-            }
-            fprintf(fp, "\n");
-        }
-    }
-}
-
 #define PS(t, s) pr_str(fp, indent, t, s)
 #define PI(t, s) pr_int(fp, indent, t, s)
 #define PSTEP(t, s) pr_int64(fp, indent, t, s)
@@ -1009,12 +950,7 @@ void pr_inputrec(FILE *fp, int indent, const char *title, const t_inputrec *ir,
         }
 
         /* ELECTRIC FIELDS */
-        pr_cosine(fp, indent, "E-x", &(ir->ex[XX]), bMDPformat);
-        pr_cosine(fp, indent, "E-xt", &(ir->et[XX]), bMDPformat);
-        pr_cosine(fp, indent, "E-y", &(ir->ex[YY]), bMDPformat);
-        pr_cosine(fp, indent, "E-yt", &(ir->et[YY]), bMDPformat);
-        pr_cosine(fp, indent, "E-z", &(ir->ex[ZZ]), bMDPformat);
-        pr_cosine(fp, indent, "E-zt", &(ir->et[ZZ]), bMDPformat);
+        ir->efield->printParameters(fp, indent);
 
         /* ION/WATER SWAPPING FOR COMPUTATIONAL ELECTROPHYSIOLOGY */
         PS("swapcoords", ESWAPTYPE(ir->eSwapCoords));
@@ -1040,6 +976,298 @@ void pr_inputrec(FILE *fp, int indent, const char *title, const t_inputrec *ir,
 #undef PR
 #undef PI
 
+static void cmp_grpopts(FILE *fp, const t_grpopts *opt1, const t_grpopts *opt2, real ftol, real abstol)
+{
+    int  i, j;
+    char buf1[256], buf2[256];
+
+    cmp_int(fp, "inputrec->grpopts.ngtc", -1,  opt1->ngtc, opt2->ngtc);
+    cmp_int(fp, "inputrec->grpopts.ngacc", -1, opt1->ngacc, opt2->ngacc);
+    cmp_int(fp, "inputrec->grpopts.ngfrz", -1, opt1->ngfrz, opt2->ngfrz);
+    cmp_int(fp, "inputrec->grpopts.ngener", -1, opt1->ngener, opt2->ngener);
+    for (i = 0; (i < std::min(opt1->ngtc, opt2->ngtc)); i++)
+    {
+        cmp_real(fp, "inputrec->grpopts.nrdf", i, opt1->nrdf[i], opt2->nrdf[i], ftol, abstol);
+        cmp_real(fp, "inputrec->grpopts.ref_t", i, opt1->ref_t[i], opt2->ref_t[i], ftol, abstol);
+        cmp_real(fp, "inputrec->grpopts.tau_t", i, opt1->tau_t[i], opt2->tau_t[i], ftol, abstol);
+        cmp_int(fp, "inputrec->grpopts.annealing", i, opt1->annealing[i], opt2->annealing[i]);
+        cmp_int(fp, "inputrec->grpopts.anneal_npoints", i,
+                opt1->anneal_npoints[i], opt2->anneal_npoints[i]);
+        if (opt1->anneal_npoints[i] == opt2->anneal_npoints[i])
+        {
+            sprintf(buf1, "inputrec->grpopts.anneal_time[%d]", i);
+            sprintf(buf2, "inputrec->grpopts.anneal_temp[%d]", i);
+            for (j = 0; j < opt1->anneal_npoints[i]; j++)
+            {
+                cmp_real(fp, buf1, j, opt1->anneal_time[i][j], opt2->anneal_time[i][j], ftol, abstol);
+                cmp_real(fp, buf2, j, opt1->anneal_temp[i][j], opt2->anneal_temp[i][j], ftol, abstol);
+            }
+        }
+    }
+    if (opt1->ngener == opt2->ngener)
+    {
+        for (i = 0; i < opt1->ngener; i++)
+        {
+            for (j = i; j < opt1->ngener; j++)
+            {
+                sprintf(buf1, "inputrec->grpopts.egp_flags[%d]", i);
+                cmp_int(fp, buf1, j,
+                        opt1->egp_flags[opt1->ngener*i+j],
+                        opt2->egp_flags[opt1->ngener*i+j]);
+            }
+        }
+    }
+    for (i = 0; (i < std::min(opt1->ngacc, opt2->ngacc)); i++)
+    {
+        cmp_rvec(fp, "inputrec->grpopts.acc", i, opt1->acc[i], opt2->acc[i], ftol, abstol);
+    }
+    for (i = 0; (i < std::min(opt1->ngfrz, opt2->ngfrz)); i++)
+    {
+        cmp_ivec(fp, "inputrec->grpopts.nFreeze", i, opt1->nFreeze[i], opt2->nFreeze[i]);
+    }
+}
+
+static void cmp_pull(FILE *fp)
+{
+    fprintf(fp, "WARNING: Both files use COM pulling, but comparing of the pull struct is not implemented (yet). The pull parameters could be the same or different.\n");
+}
+
+static void cmp_simtempvals(FILE *fp, const t_simtemp *simtemp1, const t_simtemp *simtemp2, int n_lambda, real ftol, real abstol)
+{
+    int i;
+    cmp_int(fp, "inputrec->simtempvals->eSimTempScale", -1, simtemp1->eSimTempScale, simtemp2->eSimTempScale);
+    cmp_real(fp, "inputrec->simtempvals->simtemp_high", -1, simtemp1->simtemp_high, simtemp2->simtemp_high, ftol, abstol);
+    cmp_real(fp, "inputrec->simtempvals->simtemp_low", -1, simtemp1->simtemp_low, simtemp2->simtemp_low, ftol, abstol);
+    for (i = 0; i < n_lambda; i++)
+    {
+        cmp_real(fp, "inputrec->simtempvals->temperatures", -1, simtemp1->temperatures[i], simtemp2->temperatures[i], ftol, abstol);
+    }
+}
+
+static void cmp_expandedvals(FILE *fp, const t_expanded *expand1, const t_expanded *expand2, int n_lambda, real ftol, real abstol)
+{
+    int i;
+
+    cmp_bool(fp, "inputrec->fepvals->bInit_weights", -1, expand1->bInit_weights, expand2->bInit_weights);
+    cmp_bool(fp, "inputrec->fepvals->bWLoneovert", -1, expand1->bWLoneovert, expand2->bWLoneovert);
+
+    for (i = 0; i < n_lambda; i++)
+    {
+        cmp_real(fp, "inputrec->expandedvals->init_lambda_weights", -1,
+                 expand1->init_lambda_weights[i], expand2->init_lambda_weights[i], ftol, abstol);
+    }
+
+    cmp_int(fp, "inputrec->expandedvals->lambda-stats", -1, expand1->elamstats, expand2->elamstats);
+    cmp_int(fp, "inputrec->expandedvals->lambda-mc-move", -1, expand1->elmcmove, expand2->elmcmove);
+    cmp_int(fp, "inputrec->expandedvals->lmc-repeats", -1, expand1->lmc_repeats, expand2->lmc_repeats);
+    cmp_int(fp, "inputrec->expandedvals->lmc-gibbsdelta", -1, expand1->gibbsdeltalam, expand2->gibbsdeltalam);
+    cmp_int(fp, "inputrec->expandedvals->lmc-forced-nstart", -1, expand1->lmc_forced_nstart, expand2->lmc_forced_nstart);
+    cmp_int(fp, "inputrec->expandedvals->lambda-weights-equil", -1, expand1->elmceq, expand2->elmceq);
+    cmp_int(fp, "inputrec->expandedvals->,weight-equil-number-all-lambda", -1, expand1->equil_n_at_lam, expand2->equil_n_at_lam);
+    cmp_int(fp, "inputrec->expandedvals->weight-equil-number-samples", -1, expand1->equil_samples, expand2->equil_samples);
+    cmp_int(fp, "inputrec->expandedvals->weight-equil-number-steps", -1, expand1->equil_steps, expand2->equil_steps);
+    cmp_real(fp, "inputrec->expandedvals->weight-equil-wl-delta", -1, expand1->equil_wl_delta, expand2->equil_wl_delta, ftol, abstol);
+    cmp_real(fp, "inputrec->expandedvals->weight-equil-count-ratio", -1, expand1->equil_ratio, expand2->equil_ratio, ftol, abstol);
+    cmp_bool(fp, "inputrec->expandedvals->symmetrized-transition-matrix", -1, expand1->bSymmetrizedTMatrix, expand2->bSymmetrizedTMatrix);
+    cmp_int(fp, "inputrec->expandedvals->nstTij", -1, expand1->nstTij, expand2->nstTij);
+    cmp_int(fp, "inputrec->expandedvals->mininum-var-min", -1, expand1->minvarmin, expand2->minvarmin); /*default is reasonable */
+    cmp_int(fp, "inputrec->expandedvals->weight-c-range", -1, expand1->c_range, expand2->c_range);      /* default is just C=0 */
+    cmp_real(fp, "inputrec->expandedvals->wl-scale", -1, expand1->wl_scale, expand2->wl_scale, ftol, abstol);
+    cmp_real(fp, "inputrec->expandedvals->init-wl-delta", -1, expand1->init_wl_delta, expand2->init_wl_delta, ftol, abstol);
+    cmp_real(fp, "inputrec->expandedvals->wl-ratio", -1, expand1->wl_ratio, expand2->wl_ratio, ftol, abstol);
+    cmp_int(fp, "inputrec->expandedvals->nstexpanded", -1, expand1->nstexpanded, expand2->nstexpanded);
+    cmp_int(fp, "inputrec->expandedvals->lmc-seed", -1, expand1->lmc_seed, expand2->lmc_seed);
+    cmp_real(fp, "inputrec->expandedvals->mc-temperature", -1, expand1->mc_temp, expand2->mc_temp, ftol, abstol);
+}
+
+static void cmp_fepvals(FILE *fp, const t_lambda *fep1, const t_lambda *fep2, real ftol, real abstol)
+{
+    int i, j;
+    cmp_int(fp, "inputrec->nstdhdl", -1, fep1->nstdhdl, fep2->nstdhdl);
+    cmp_double(fp, "inputrec->fepvals->init_fep_state", -1, fep1->init_fep_state, fep2->init_fep_state, ftol, abstol);
+    cmp_double(fp, "inputrec->fepvals->delta_lambda", -1, fep1->delta_lambda, fep2->delta_lambda, ftol, abstol);
+    cmp_int(fp, "inputrec->fepvals->n_lambda", -1, fep1->n_lambda, fep2->n_lambda);
+    for (i = 0; i < efptNR; i++)
+    {
+        for (j = 0; j < std::min(fep1->n_lambda, fep2->n_lambda); j++)
+        {
+            cmp_double(fp, "inputrec->fepvals->all_lambda", -1, fep1->all_lambda[i][j], fep2->all_lambda[i][j], ftol, abstol);
+        }
+    }
+    cmp_int(fp, "inputrec->fepvals->lambda_neighbors", 1, fep1->lambda_neighbors,
+            fep2->lambda_neighbors);
+    cmp_real(fp, "inputrec->fepvals->sc_alpha", -1, fep1->sc_alpha, fep2->sc_alpha, ftol, abstol);
+    cmp_int(fp, "inputrec->fepvals->sc_power", -1, fep1->sc_power, fep2->sc_power);
+    cmp_real(fp, "inputrec->fepvals->sc_r_power", -1, fep1->sc_r_power, fep2->sc_r_power, ftol, abstol);
+    cmp_real(fp, "inputrec->fepvals->sc_sigma", -1, fep1->sc_sigma, fep2->sc_sigma, ftol, abstol);
+    cmp_int(fp, "inputrec->fepvals->edHdLPrintEnergy", -1, fep1->edHdLPrintEnergy, fep1->edHdLPrintEnergy);
+    cmp_bool(fp, "inputrec->fepvals->bScCoul", -1, fep1->bScCoul, fep1->bScCoul);
+    cmp_int(fp, "inputrec->separate_dhdl_file", -1, fep1->separate_dhdl_file, fep2->separate_dhdl_file);
+    cmp_int(fp, "inputrec->dhdl_derivatives", -1, fep1->dhdl_derivatives, fep2->dhdl_derivatives);
+    cmp_int(fp, "inputrec->dh_hist_size", -1, fep1->dh_hist_size, fep2->dh_hist_size);
+    cmp_double(fp, "inputrec->dh_hist_spacing", -1, fep1->dh_hist_spacing, fep2->dh_hist_spacing, ftol, abstol);
+}
+
+void cmp_inputrec(FILE *fp, const t_inputrec *ir1, const t_inputrec *ir2, real ftol, real abstol)
+{
+    fprintf(fp, "comparing inputrec\n");
+
+    /* gcc 2.96 doesnt like these defines at all, but issues a huge list
+     * of warnings. Maybe it will change in future versions, but for the
+     * moment I've spelled them out instead. /EL 000820
+     * #define CIB(s) cmp_int(fp,"inputrec->"#s,0,ir1->##s,ir2->##s)
+     * #define CII(s) cmp_int(fp,"inputrec->"#s,0,ir1->##s,ir2->##s)
+     * #define CIR(s) cmp_real(fp,"inputrec->"#s,0,ir1->##s,ir2->##s,ftol)
+     */
+    cmp_int(fp, "inputrec->eI", -1, ir1->eI, ir2->eI);
+    cmp_int64(fp, "inputrec->nsteps", ir1->nsteps, ir2->nsteps);
+    cmp_int64(fp, "inputrec->init_step", ir1->init_step, ir2->init_step);
+    cmp_int(fp, "inputrec->simulation_part", -1, ir1->simulation_part, ir2->simulation_part);
+    cmp_int(fp, "inputrec->ePBC", -1, ir1->ePBC, ir2->ePBC);
+    cmp_int(fp, "inputrec->bPeriodicMols", -1, ir1->bPeriodicMols, ir2->bPeriodicMols);
+    cmp_int(fp, "inputrec->cutoff_scheme", -1, ir1->cutoff_scheme, ir2->cutoff_scheme);
+    cmp_int(fp, "inputrec->ns_type", -1, ir1->ns_type, ir2->ns_type);
+    cmp_int(fp, "inputrec->nstlist", -1, ir1->nstlist, ir2->nstlist);
+    cmp_int(fp, "inputrec->nstcomm", -1, ir1->nstcomm, ir2->nstcomm);
+    cmp_int(fp, "inputrec->comm_mode", -1, ir1->comm_mode, ir2->comm_mode);
+    cmp_int(fp, "inputrec->nstlog", -1, ir1->nstlog, ir2->nstlog);
+    cmp_int(fp, "inputrec->nstxout", -1, ir1->nstxout, ir2->nstxout);
+    cmp_int(fp, "inputrec->nstvout", -1, ir1->nstvout, ir2->nstvout);
+    cmp_int(fp, "inputrec->nstfout", -1, ir1->nstfout, ir2->nstfout);
+    cmp_int(fp, "inputrec->nstcalcenergy", -1, ir1->nstcalcenergy, ir2->nstcalcenergy);
+    cmp_int(fp, "inputrec->nstenergy", -1, ir1->nstenergy, ir2->nstenergy);
+    cmp_int(fp, "inputrec->nstxout_compressed", -1, ir1->nstxout_compressed, ir2->nstxout_compressed);
+    cmp_double(fp, "inputrec->init_t", -1, ir1->init_t, ir2->init_t, ftol, abstol);
+    cmp_double(fp, "inputrec->delta_t", -1, ir1->delta_t, ir2->delta_t, ftol, abstol);
+    cmp_real(fp, "inputrec->x_compression_precision", -1, ir1->x_compression_precision, ir2->x_compression_precision, ftol, abstol);
+    cmp_real(fp, "inputrec->fourierspacing", -1, ir1->fourier_spacing, ir2->fourier_spacing, ftol, abstol);
+    cmp_int(fp, "inputrec->nkx", -1, ir1->nkx, ir2->nkx);
+    cmp_int(fp, "inputrec->nky", -1, ir1->nky, ir2->nky);
+    cmp_int(fp, "inputrec->nkz", -1, ir1->nkz, ir2->nkz);
+    cmp_int(fp, "inputrec->pme_order", -1, ir1->pme_order, ir2->pme_order);
+    cmp_real(fp, "inputrec->ewald_rtol", -1, ir1->ewald_rtol, ir2->ewald_rtol, ftol, abstol);
+    cmp_int(fp, "inputrec->ewald_geometry", -1, ir1->ewald_geometry, ir2->ewald_geometry);
+    cmp_real(fp, "inputrec->epsilon_surface", -1, ir1->epsilon_surface, ir2->epsilon_surface, ftol, abstol);
+    cmp_int(fp, "inputrec->bContinuation", -1, ir1->bContinuation, ir2->bContinuation);
+    cmp_int(fp, "inputrec->bShakeSOR", -1, ir1->bShakeSOR, ir2->bShakeSOR);
+    cmp_int(fp, "inputrec->etc", -1, ir1->etc, ir2->etc);
+    cmp_int(fp, "inputrec->bPrintNHChains", -1, ir1->bPrintNHChains, ir2->bPrintNHChains);
+    cmp_int(fp, "inputrec->epc", -1, ir1->epc, ir2->epc);
+    cmp_int(fp, "inputrec->epct", -1, ir1->epct, ir2->epct);
+    cmp_real(fp, "inputrec->tau_p", -1, ir1->tau_p, ir2->tau_p, ftol, abstol);
+    cmp_rvec(fp, "inputrec->ref_p(x)", -1, ir1->ref_p[XX], ir2->ref_p[XX], ftol, abstol);
+    cmp_rvec(fp, "inputrec->ref_p(y)", -1, ir1->ref_p[YY], ir2->ref_p[YY], ftol, abstol);
+    cmp_rvec(fp, "inputrec->ref_p(z)", -1, ir1->ref_p[ZZ], ir2->ref_p[ZZ], ftol, abstol);
+    cmp_rvec(fp, "inputrec->compress(x)", -1, ir1->compress[XX], ir2->compress[XX], ftol, abstol);
+    cmp_rvec(fp, "inputrec->compress(y)", -1, ir1->compress[YY], ir2->compress[YY], ftol, abstol);
+    cmp_rvec(fp, "inputrec->compress(z)", -1, ir1->compress[ZZ], ir2->compress[ZZ], ftol, abstol);
+    cmp_int(fp, "refcoord_scaling", -1, ir1->refcoord_scaling, ir2->refcoord_scaling);
+    cmp_rvec(fp, "inputrec->posres_com", -1, ir1->posres_com, ir2->posres_com, ftol, abstol);
+    cmp_rvec(fp, "inputrec->posres_comB", -1, ir1->posres_comB, ir2->posres_comB, ftol, abstol);
+    cmp_real(fp, "inputrec->verletbuf_tol", -1, ir1->verletbuf_tol, ir2->verletbuf_tol, ftol, abstol);
+    cmp_real(fp, "inputrec->rlist", -1, ir1->rlist, ir2->rlist, ftol, abstol);
+    cmp_real(fp, "inputrec->rtpi", -1, ir1->rtpi, ir2->rtpi, ftol, abstol);
+    cmp_int(fp, "inputrec->coulombtype", -1, ir1->coulombtype, ir2->coulombtype);
+    cmp_int(fp, "inputrec->coulomb_modifier", -1, ir1->coulomb_modifier, ir2->coulomb_modifier);
+    cmp_real(fp, "inputrec->rcoulomb_switch", -1, ir1->rcoulomb_switch, ir2->rcoulomb_switch, ftol, abstol);
+    cmp_real(fp, "inputrec->rcoulomb", -1, ir1->rcoulomb, ir2->rcoulomb, ftol, abstol);
+    cmp_int(fp, "inputrec->vdwtype", -1, ir1->vdwtype, ir2->vdwtype);
+    cmp_int(fp, "inputrec->vdw_modifier", -1, ir1->vdw_modifier, ir2->vdw_modifier);  cmp_real(fp, "inputrec->rvdw_switch", -1, ir1->rvdw_switch, ir2->rvdw_switch, ftol, abstol);
+    cmp_real(fp, "inputrec->rvdw", -1, ir1->rvdw, ir2->rvdw, ftol, abstol);
+    cmp_real(fp, "inputrec->epsilon_r", -1, ir1->epsilon_r, ir2->epsilon_r, ftol, abstol);
+    cmp_real(fp, "inputrec->epsilon_rf", -1, ir1->epsilon_rf, ir2->epsilon_rf, ftol, abstol);
+    cmp_real(fp, "inputrec->tabext", -1, ir1->tabext, ir2->tabext, ftol, abstol);
+    cmp_int(fp, "inputrec->implicit_solvent", -1, ir1->implicit_solvent, ir2->implicit_solvent);
+    cmp_int(fp, "inputrec->gb_algorithm", -1, ir1->gb_algorithm, ir2->gb_algorithm);
+    cmp_int(fp, "inputrec->nstgbradii", -1, ir1->nstgbradii, ir2->nstgbradii);
+    cmp_real(fp, "inputrec->rgbradii", -1, ir1->rgbradii, ir2->rgbradii, ftol, abstol);
+    cmp_real(fp, "inputrec->gb_saltconc", -1, ir1->gb_saltconc, ir2->gb_saltconc, ftol, abstol);
+    cmp_real(fp, "inputrec->gb_epsilon_solvent", -1, ir1->gb_epsilon_solvent, ir2->gb_epsilon_solvent, ftol, abstol);
+    cmp_real(fp, "inputrec->gb_obc_alpha", -1, ir1->gb_obc_alpha, ir2->gb_obc_alpha, ftol, abstol);
+    cmp_real(fp, "inputrec->gb_obc_beta", -1, ir1->gb_obc_beta, ir2->gb_obc_beta, ftol, abstol);
+    cmp_real(fp, "inputrec->gb_obc_gamma", -1, ir1->gb_obc_gamma, ir2->gb_obc_gamma, ftol, abstol);
+    cmp_real(fp, "inputrec->gb_dielectric_offset", -1, ir1->gb_dielectric_offset, ir2->gb_dielectric_offset, ftol, abstol);
+    cmp_int(fp, "inputrec->sa_algorithm", -1, ir1->sa_algorithm, ir2->sa_algorithm);
+    cmp_real(fp, "inputrec->sa_surface_tension", -1, ir1->sa_surface_tension, ir2->sa_surface_tension, ftol, abstol);
+
+    cmp_int(fp, "inputrec->eDispCorr", -1, ir1->eDispCorr, ir2->eDispCorr);
+    cmp_real(fp, "inputrec->shake_tol", -1, ir1->shake_tol, ir2->shake_tol, ftol, abstol);
+    cmp_int(fp, "inputrec->efep", -1, ir1->efep, ir2->efep);
+    cmp_fepvals(fp, ir1->fepvals, ir2->fepvals, ftol, abstol);
+    cmp_int(fp, "inputrec->bSimTemp", -1, ir1->bSimTemp, ir2->bSimTemp);
+    if ((ir1->bSimTemp == ir2->bSimTemp) && (ir1->bSimTemp))
+    {
+        cmp_simtempvals(fp, ir1->simtempvals, ir2->simtempvals, std::min(ir1->fepvals->n_lambda, ir2->fepvals->n_lambda), ftol, abstol);
+    }
+    cmp_int(fp, "inputrec->bExpanded", -1, ir1->bExpanded, ir2->bExpanded);
+    if ((ir1->bExpanded == ir2->bExpanded) && (ir1->bExpanded))
+    {
+        cmp_expandedvals(fp, ir1->expandedvals, ir2->expandedvals, std::min(ir1->fepvals->n_lambda, ir2->fepvals->n_lambda), ftol, abstol);
+    }
+    cmp_int(fp, "inputrec->nwall", -1, ir1->nwall, ir2->nwall);
+    cmp_int(fp, "inputrec->wall_type", -1, ir1->wall_type, ir2->wall_type);
+    cmp_int(fp, "inputrec->wall_atomtype[0]", -1, ir1->wall_atomtype[0], ir2->wall_atomtype[0]);
+    cmp_int(fp, "inputrec->wall_atomtype[1]", -1, ir1->wall_atomtype[1], ir2->wall_atomtype[1]);
+    cmp_real(fp, "inputrec->wall_density[0]", -1, ir1->wall_density[0], ir2->wall_density[0], ftol, abstol);
+    cmp_real(fp, "inputrec->wall_density[1]", -1, ir1->wall_density[1], ir2->wall_density[1], ftol, abstol);
+    cmp_real(fp, "inputrec->wall_ewald_zfac", -1, ir1->wall_ewald_zfac, ir2->wall_ewald_zfac, ftol, abstol);
+
+    cmp_bool(fp, "inputrec->bPull", -1, ir1->bPull, ir2->bPull);
+    if (ir1->bPull && ir2->bPull)
+    {
+        cmp_pull(fp);
+    }
+
+    cmp_int(fp, "inputrec->eDisre", -1, ir1->eDisre, ir2->eDisre);
+    cmp_real(fp, "inputrec->dr_fc", -1, ir1->dr_fc, ir2->dr_fc, ftol, abstol);
+    cmp_int(fp, "inputrec->eDisreWeighting", -1, ir1->eDisreWeighting, ir2->eDisreWeighting);
+    cmp_int(fp, "inputrec->bDisreMixed", -1, ir1->bDisreMixed, ir2->bDisreMixed);
+    cmp_int(fp, "inputrec->nstdisreout", -1, ir1->nstdisreout, ir2->nstdisreout);
+    cmp_real(fp, "inputrec->dr_tau", -1, ir1->dr_tau, ir2->dr_tau, ftol, abstol);
+    cmp_real(fp, "inputrec->orires_fc", -1, ir1->orires_fc, ir2->orires_fc, ftol, abstol);
+    cmp_real(fp, "inputrec->orires_tau", -1, ir1->orires_tau, ir2->orires_tau, ftol, abstol);
+    cmp_int(fp, "inputrec->nstorireout", -1, ir1->nstorireout, ir2->nstorireout);
+    cmp_real(fp, "inputrec->em_stepsize", -1, ir1->em_stepsize, ir2->em_stepsize, ftol, abstol);
+    cmp_real(fp, "inputrec->em_tol", -1, ir1->em_tol, ir2->em_tol, ftol, abstol);
+    cmp_int(fp, "inputrec->niter", -1, ir1->niter, ir2->niter);
+    cmp_real(fp, "inputrec->fc_stepsize", -1, ir1->fc_stepsize, ir2->fc_stepsize, ftol, abstol);
+    cmp_int(fp, "inputrec->nstcgsteep", -1, ir1->nstcgsteep, ir2->nstcgsteep);
+    cmp_int(fp, "inputrec->nbfgscorr", 0, ir1->nbfgscorr, ir2->nbfgscorr);
+    cmp_int(fp, "inputrec->eConstrAlg", -1, ir1->eConstrAlg, ir2->eConstrAlg);
+    cmp_int(fp, "inputrec->nProjOrder", -1, ir1->nProjOrder, ir2->nProjOrder);
+    cmp_real(fp, "inputrec->LincsWarnAngle", -1, ir1->LincsWarnAngle, ir2->LincsWarnAngle, ftol, abstol);
+    cmp_int(fp, "inputrec->nLincsIter", -1, ir1->nLincsIter, ir2->nLincsIter);
+    cmp_real(fp, "inputrec->bd_fric", -1, ir1->bd_fric, ir2->bd_fric, ftol, abstol);
+    cmp_int64(fp, "inputrec->ld_seed", ir1->ld_seed, ir2->ld_seed);
+    cmp_real(fp, "inputrec->cos_accel", -1, ir1->cos_accel, ir2->cos_accel, ftol, abstol);
+    cmp_rvec(fp, "inputrec->deform(a)", -1, ir1->deform[XX], ir2->deform[XX], ftol, abstol);
+    cmp_rvec(fp, "inputrec->deform(b)", -1, ir1->deform[YY], ir2->deform[YY], ftol, abstol);
+    cmp_rvec(fp, "inputrec->deform(c)", -1, ir1->deform[ZZ], ir2->deform[ZZ], ftol, abstol);
+
+
+    cmp_int(fp, "inputrec->userint1", -1, ir1->userint1, ir2->userint1);
+    cmp_int(fp, "inputrec->userint2", -1, ir1->userint2, ir2->userint2);
+    cmp_int(fp, "inputrec->userint3", -1, ir1->userint3, ir2->userint3);
+    cmp_int(fp, "inputrec->userint4", -1, ir1->userint4, ir2->userint4);
+    cmp_real(fp, "inputrec->userreal1", -1, ir1->userreal1, ir2->userreal1, ftol, abstol);
+    cmp_real(fp, "inputrec->userreal2", -1, ir1->userreal2, ir2->userreal2, ftol, abstol);
+    cmp_real(fp, "inputrec->userreal3", -1, ir1->userreal3, ir2->userreal3, ftol, abstol);
+    cmp_real(fp, "inputrec->userreal4", -1, ir1->userreal4, ir2->userreal4, ftol, abstol);
+    cmp_grpopts(fp, &(ir1->opts), &(ir2->opts), ftol, abstol);
+    ir1->efield->compare(fp, ir2->efield, ftol, abstol);
+}
+
+void comp_pull_AB(FILE *fp, pull_params_t *pull, real ftol, real abstol)
+{
+    int i;
+
+    for (i = 0; i < pull->ncoord; i++)
+    {
+        fprintf(fp, "comparing pull coord %d\n", i);
+        cmp_real(fp, "pull-coord->k", -1, pull->coord[i].k, pull->coord[i].kB, ftol, abstol);
+    }
+}
+
 gmx_bool inputrecDeform(const t_inputrec *ir)
 {
     return (ir->deform[XX][XX] != 0 || ir->deform[YY][YY] != 0 || ir->deform[ZZ][ZZ] != 0 ||
@@ -1063,11 +1291,6 @@ gmx_bool inputrecNeedMutot(const t_inputrec *ir)
             (ir->ewald_geometry == eewg3DC || ir->epsilon_surface != 0));
 }
 
-gmx_bool inputrecElecField(const t_inputrec *ir)
-{
-    return (ir->ex[XX].n > 0 || ir->ex[YY].n > 0 || ir->ex[ZZ].n > 0);
-}
-
 gmx_bool inputrecExclForces(const t_inputrec *ir)
 {
     return (EEL_FULL(ir->coulombtype) || (EEL_RF(ir->coulombtype)) ||
index 2f898195b257665cc6f7f086481f7734d70d1842..abf5d0ab3bdd9f0d098a7335bacf447f11c963d5 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 
-typedef struct {
-    //! Number of terms
-    int   n;
-    //! Coeffients (V / nm)
-    real *a;
-    //! Phase angles
-    real *phi;
-} t_cosines;
-
-typedef struct {
-    real E0;            /* Field strength (V/nm)                        */
-    real omega;         /* Frequency (1/ps)                             */
-    real t0;            /* Centre of the Gaussian pulse (ps)            */
-    real sigma;         /* Width of the Gaussian pulse (FWHM) (ps)      */
-} t_efield;
-
 #define EGP_EXCL  (1<<0)
 #define EGP_TABLE (1<<1)
 
+struct gmx_output_env_t;
+struct pull_params_t;
+struct t_commrec;
+struct t_fileio;
+struct t_filenm;
+struct t_forcerec;
+struct t_inpfile;
+struct warninp;
+
+namespace gmx
+{
+
+class IKeyValueTreeTransformRules;
+class IOptionsContainerWithSections;
+
+/*! \libinternal \brief
+ * Inputrec extension interface for a mdrun module.
+ *
+ * This interface provides a mechanism for additional modules to contribute
+ * data that traditionally has been kept in t_inputrec. This is essentially
+ * parameters read from an mdp file and subsequently stored in a tpr file.
+ * The functionality to broadcast, compare, and print these parameters
+ * currently needs to be provided separately, but this should simplify
+ * significantly if/when we move to a more structured file format (both for mdp
+ * and tpr) that allows a generic representation for code that does not need to
+ * know the interpretation of the values.
+ *
+ * For now, this interface also includes some unrelated methods (initOutput(),
+ * finishOutput(), initForcerec()), because t_inputrec is used as a container
+ * to pass references to the modules around.
+ * See MDModules for more information on the general approach and future
+ * considerations.
+ */
+class IInputRecExtension
+{
+    public:
+        virtual ~IInputRecExtension() {}
+
+        /*! \brief Read or write tpr file
+         *
+         * Read or write the necessary data from a tpr file. The routine is responsible
+         * for consistency, such that all data belonging to this module is read or written.
+         * \param[inout] fio Gromacs file descriptor
+         * \param[in]    bRead boolean determines whether we are reading or writing
+         */
+        virtual void doTpxIO(t_fileio *fio, bool bRead) = 0;
+
+        /*! \brief
+         * Initializes a transform from mdp values to sectioned options.
+         *
+         * The transform is specified from a flat KeyValueTreeObject that
+         * contains each mdp value as a property, to a structure which is then
+         * assigned to the options defined with initMdpOptions().
+         */
+        virtual void initMdpTransform(IKeyValueTreeTransformRules *transform) = 0;
+        /*! \brief
+         * Defines input (mdp) parameters for this extension.
+         */
+        virtual void initMdpOptions(IOptionsContainerWithSections *options) = 0;
+
+        /*! \brief Broadcast input parameters to all ranks
+         *
+         * \param[in] cr  Communication record, gromacs structure
+         */
+        virtual void broadCast(const t_commrec *cr)     = 0;
+
+        /*! \brief compare a section of two input record structures
+         *
+         * Routine is used in gmx check.
+         * \param[in]    fp     File pointer
+         * \param[inout] field2 Electric field
+         * \param[in]    reltol Relative tolerance
+         * \param[in]    abstol Absolute tolerance
+         */
+        virtual void compare(FILE                          *fp,
+                             const gmx::IInputRecExtension *field2,
+                             real                           reltol,
+                             real                           abstol)  = 0;
+
+        /*! \brief Print parameters belonging to this class to a file
+         *
+         * \param[in] fp     File pointer
+         * \param[in] indent Initial indentation level for printing
+         */
+        virtual void printParameters(FILE *fp, int indent)           = 0;
+
+        /*! \brief Initiate output parameters
+         *
+         * \param[in] fplog File pointer for log messages
+         * \param[in] nfile Number of files
+         * \param[in] fnm   Array of filenames and properties
+         * \param[in] bAppendFiles Whether or not we should append to files
+         * \param[in] oenv  The output environment for xvg files
+         */
+        virtual void initOutput(FILE *fplog, int nfile, const t_filenm fnm[],
+                                bool bAppendFiles, const gmx_output_env_t *oenv) = 0;
+
+        //! Finalize output
+        virtual void finishOutput()               = 0;
+
+        /*! \brief Set/initiate relevant options in the forcerec structure
+         *
+         * \param[inout] fr The forcerec structure
+         */
+        virtual void initForcerec(t_forcerec *fr) = 0;
+};
+
+} // namespace gmx
+
 typedef struct t_grpopts {
     int       ngtc;           /* # T-Coupl groups                        */
     int       nhchainlength;  /* # of nose-hoover chains per group       */
@@ -247,7 +340,8 @@ typedef struct t_swapcoords {
                                             * swapcoords.cpp                               */
 } t_swapcoords;
 
-typedef struct t_inputrec {
+struct t_inputrec
+{
     int             eI;                      /* Integration method                 */
     gmx_int64_t     nsteps;                  /* number of steps to be taken                    */
     int             simulation_part;         /* Used in checkpointing to separate chunks */
@@ -368,37 +462,36 @@ typedef struct t_inputrec {
     struct pull_t        *pull_work;         /* The COM pull force calculation data structure; TODO this pointer should live somewhere else */
 
     /* Enforced rotation data */
-    gmx_bool        bRot;                    /* Calculate enforced rotation potential(s)?    */
-    t_rot          *rot;                     /* The data for enforced rotation potentials    */
-
-    int             eSwapCoords;             /* Do ion/water position exchanges (CompEL)?    */
-    t_swapcoords   *swap;
-
-    gmx_bool        bIMD;                    /* Allow interactive MD sessions for this .tpr? */
-    t_IMD          *imd;                     /* Interactive molecular dynamics               */
-
-    real            cos_accel;               /* Acceleration for viscosity calculation       */
-    tensor          deform;                  /* Triclinic deformation velocities (nm/ps)     */
-    int             userint1;                /* User determined parameters                   */
-    int             userint2;
-    int             userint3;
-    int             userint4;
-    real            userreal1;
-    real            userreal2;
-    real            userreal3;
-    real            userreal4;
-    t_grpopts       opts;          /* Group options                            */
-    t_cosines       ex[DIM];       /* Electric field stuff     (spatial part)          */
-    t_cosines       et[DIM];       /* Electric field stuff     (time part)             */
-    gmx_bool        bQMMM;         /* QM/MM calculation                            */
-    int             QMconstraints; /* constraints on QM bonds                      */
-    int             QMMMscheme;    /* Scheme: ONIOM or normal                      */
-    real            scalefactor;   /* factor for scaling the MM charges in QM calc.*/
+    gmx_bool                 bRot;           /* Calculate enforced rotation potential(s)?    */
+    t_rot                   *rot;            /* The data for enforced rotation potentials    */
+
+    int                      eSwapCoords;    /* Do ion/water position exchanges (CompEL)?    */
+    t_swapcoords            *swap;
+
+    gmx_bool                 bIMD;           /* Allow interactive MD sessions for this .tpr? */
+    t_IMD                   *imd;            /* Interactive molecular dynamics               */
+
+    real                     cos_accel;      /* Acceleration for viscosity calculation       */
+    tensor                   deform;         /* Triclinic deformation velocities (nm/ps)     */
+    int                      userint1;       /* User determined parameters                   */
+    int                      userint2;
+    int                      userint3;
+    int                      userint4;
+    real                     userreal1;
+    real                     userreal2;
+    real                     userreal3;
+    real                     userreal4;
+    t_grpopts                opts;          /* Group options                           */
+    gmx::IInputRecExtension *efield;        /* Applied electric field                       */
+    gmx_bool                 bQMMM;         /* QM/MM calculation                            */
+    int                      QMconstraints; /* constraints on QM bonds                      */
+    int                      QMMMscheme;    /* Scheme: ONIOM or normal                      */
+    real                     scalefactor;   /* factor for scaling the MM charges in QM calc.*/
 
     /* Fields for removed features go here (better caching) */
     gmx_bool        bAdress;       // Whether AdResS is enabled - always false if a valid .tpr was read
     gmx_bool        useTwinRange;  // Whether twin-range scheme is active - always false if a valid .tpr was read
-} t_inputrec;
+};
 
 int ir_optimal_nstcalcenergy(const t_inputrec *ir);
 
@@ -436,14 +529,6 @@ gmx_bool ir_vdw_is_zero_at_cutoff(const t_inputrec *ir);
  */
 gmx_bool ir_vdw_might_be_zero_at_cutoff(const t_inputrec *ir);
 
-/*! \brief Initiate input record structure
- *
- * Initialiazes all the arrays and pointers to NULL.
- *
- * \param[in] ir Inputrec must be pre-allocated
- */
-void init_inputrec(t_inputrec *ir);
-
 /*! \brief Free memory from input record.
  *
  * All arrays and pointers will be freed.
@@ -455,6 +540,11 @@ void done_inputrec(t_inputrec *ir);
 void pr_inputrec(FILE *fp, int indent, const char *title, const t_inputrec *ir,
                  gmx_bool bMDPformat);
 
+void cmp_inputrec(FILE *fp, const t_inputrec *ir1, const t_inputrec *ir2, real ftol, real abstol);
+
+void comp_pull_AB(FILE *fp, pull_params_t *pull, real ftol, real abstol);
+
+
 gmx_bool inputrecDeform(const t_inputrec *ir);
 
 gmx_bool inputrecDynamicBox(const t_inputrec *ir);
@@ -465,8 +555,6 @@ gmx_bool inputrecNeedMutot(const t_inputrec *ir);
 
 gmx_bool inputrecTwinRange(const t_inputrec *ir);
 
-gmx_bool inputrecElecField(const t_inputrec *ir);
-
 gmx_bool inputrecExclForces(const t_inputrec *ir);
 
 gmx_bool inputrecNptTrotter(const t_inputrec *ir);
index 69519ececfea9260c8038fc2b1e999ebeabd007e..064fe6ea6dd929a8622a55f11a0baedb5e3e2ac6 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -43,6 +43,7 @@
 #ifndef GMX_MDTYPES_MDATOM_H
 #define GMX_MDTYPES_MDATOM_H
 
+#include "gromacs/math/vectypes.h"
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 
@@ -77,8 +78,10 @@ typedef struct t_mdatoms {
     real                  *massB;
     //! Atomic mass in present state
     real                  *massT;
-    //! Inverse atomic mass
+    //! Inverse atomic mass per atom, 0 for vsites and shells
     real                  *invmass;
+    //! Inverse atomic mass per atom and dimension, 0 for vsites, shells and frozen dimensions
+    rvec                  *invMassPerDim;
     //! Atomic charge in A state
     real                  *chargeA;
     //! Atomic charge in B state
index 3bcf9a8987984528d83ac6097be997458624ae8b..e77586e1572e52ade5e422de61daeb6507deb48f 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 #include <algorithm>
 
 #include "gromacs/math/vec.h"
+#include "gromacs/math/veccompare.h"
 #include "gromacs/mdtypes/df_history.h"
-#include "gromacs/mdtypes/energyhistory.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
+#include "gromacs/utility/compare.h"
+#include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/smalloc.h"
 
 /* The source code in this file should be thread-safe.
@@ -69,9 +71,9 @@ static void zero_ekinstate(ekinstate_t *eks)
     eks->ekinh          = NULL;
     eks->ekinf          = NULL;
     eks->ekinh_old      = NULL;
-    eks->ekinscalef_nhc = NULL;
-    eks->ekinscaleh_nhc = NULL;
-    eks->vscale_nhc     = NULL;
+    eks->ekinscalef_nhc.resize(0);
+    eks->ekinscaleh_nhc.resize(0);
+    eks->vscale_nhc.resize(0);
     eks->dekindl        = 0;
     eks->mvcos          = 0;
 }
@@ -96,70 +98,23 @@ static void init_swapstate(swapstate_t *swapstate)
 
 void init_gtc_state(t_state *state, int ngtc, int nnhpres, int nhchainlength)
 {
-    int i, j;
-
     state->ngtc          = ngtc;
     state->nnhpres       = nnhpres;
     state->nhchainlength = nhchainlength;
-    if (state->ngtc > 0)
-    {
-        snew(state->nosehoover_xi, state->nhchainlength*state->ngtc);
-        snew(state->nosehoover_vxi, state->nhchainlength*state->ngtc);
-        snew(state->therm_integral, state->ngtc);
-        for (i = 0; i < state->ngtc; i++)
-        {
-            for (j = 0; j < state->nhchainlength; j++)
-            {
-                state->nosehoover_xi[i*state->nhchainlength + j]   = 0.0;
-                state->nosehoover_vxi[i*state->nhchainlength + j]  = 0.0;
-            }
-        }
-        for (i = 0; i < state->ngtc; i++)
-        {
-            state->therm_integral[i]  = 0.0;
-        }
-    }
-    else
-    {
-        state->nosehoover_xi  = NULL;
-        state->nosehoover_vxi = NULL;
-        state->therm_integral = NULL;
-    }
-
-    if (state->nnhpres > 0)
-    {
-        snew(state->nhpres_xi, state->nhchainlength*nnhpres);
-        snew(state->nhpres_vxi, state->nhchainlength*nnhpres);
-        for (i = 0; i < nnhpres; i++)
-        {
-            for (j = 0; j < state->nhchainlength; j++)
-            {
-                state->nhpres_xi[i*nhchainlength + j]   = 0.0;
-                state->nhpres_vxi[i*nhchainlength + j]  = 0.0;
-            }
-        }
-    }
-    else
-    {
-        state->nhpres_xi  = NULL;
-        state->nhpres_vxi = NULL;
-    }
+    state->nosehoover_xi.resize(state->nhchainlength*state->ngtc, 0);
+    state->nosehoover_vxi.resize(state->nhchainlength*state->ngtc, 0);
+    state->therm_integral.resize(state->ngtc, 0);
+    state->nhpres_xi.resize(state->nhchainlength*nnhpres, 0);
+    state->nhpres_vxi.resize(state->nhchainlength*nnhpres, 0);
 }
 
 
-void init_state(t_state *state, int natoms, int ngtc, int nnhpres, int nhchainlength, int nlambda)
+void init_state(t_state *state, int natoms, int ngtc, int nnhpres, int nhchainlength, int dfhistNumLambda)
 {
-    int i;
-
     state->natoms    = natoms;
     state->flags     = 0;
     state->fep_state = 0;
-    state->lambda    = 0;
-    snew(state->lambda, efptNR);
-    for (i = 0; i < efptNR; i++)
-    {
-        state->lambda[i] = 0;
-    }
+    state->lambda.resize(efptNR, 0);
     state->veta   = 0;
     clear_mat(state->box);
     clear_mat(state->box_rel);
@@ -168,80 +123,124 @@ void init_state(t_state *state, int natoms, int ngtc, int nnhpres, int nhchainle
     clear_mat(state->svir_prev);
     clear_mat(state->fvir_prev);
     init_gtc_state(state, ngtc, nnhpres, nhchainlength);
-    state->nalloc = state->natoms;
-    if (state->nalloc > 0)
+    if (state->natoms > 0)
     {
         /* We need to allocate one element extra, since we might use
          * (unaligned) 4-wide SIMD loads to access rvec entries.
          */
-        snew(state->x, state->nalloc + 1);
-        snew(state->v, state->nalloc + 1);
+        state->x.resize(state->natoms + 1);
+        state->v.resize(state->natoms + 1);
     }
     else
     {
-        state->x = NULL;
-        state->v = NULL;
+        state->x.resize(0);
+        state->v.resize(0);
     }
-    state->cg_p = NULL;
+    state->cg_p.resize(0);
     zero_history(&state->hist);
     zero_ekinstate(&state->ekinstate);
-    snew(state->enerhist, 1);
-    init_energyhistory(state->enerhist);
-    init_df_history(&state->dfhist, nlambda);
-    init_swapstate(&state->swapstate);
+    if (dfhistNumLambda > 0)
+    {
+        snew(state->dfhist, 1);
+        init_df_history(state->dfhist, dfhistNumLambda);
+    }
+    else
+    {
+        state->dfhist = NULL;
+    }
+    state->swapstate       = NULL;
+    state->edsamstate      = NULL;
     state->ddp_count       = 0;
     state->ddp_count_cg_gl = 0;
-    state->cg_gl           = NULL;
-    state->cg_gl_nalloc    = 0;
+    state->cg_gl.resize(0);
 }
 
-void done_state(t_state *state)
+void comp_state(const t_state *st1, const t_state *st2,
+                gmx_bool bRMSD, real ftol, real abstol)
 {
-    if (state->x)
+    int i, j, nc;
+
+    fprintf(stdout, "comparing flags\n");
+    cmp_int(stdout, "flags", -1, st1->flags, st2->flags);
+    fprintf(stdout, "comparing box\n");
+    cmp_rvecs(stdout, "box", DIM, st1->box, st2->box, FALSE, ftol, abstol);
+    fprintf(stdout, "comparing box_rel\n");
+    cmp_rvecs(stdout, "box_rel", DIM, st1->box_rel, st2->box_rel, FALSE, ftol, abstol);
+    fprintf(stdout, "comparing boxv\n");
+    cmp_rvecs(stdout, "boxv", DIM, st1->boxv, st2->boxv, FALSE, ftol, abstol);
+    if (st1->flags & (1<<estSVIR_PREV))
     {
-        sfree(state->x);
+        fprintf(stdout, "comparing shake vir_prev\n");
+        cmp_rvecs(stdout, "svir_prev", DIM, st1->svir_prev, st2->svir_prev, FALSE, ftol, abstol);
     }
-    if (state->v)
+    if (st1->flags & (1<<estFVIR_PREV))
     {
-        sfree(state->v);
+        fprintf(stdout, "comparing force vir_prev\n");
+        cmp_rvecs(stdout, "fvir_prev", DIM, st1->fvir_prev, st2->fvir_prev, FALSE, ftol, abstol);
     }
-    if (state->cg_p)
+    if (st1->flags & (1<<estPRES_PREV))
     {
-        sfree(state->cg_p);
+        fprintf(stdout, "comparing prev_pres\n");
+        cmp_rvecs(stdout, "pres_prev", DIM, st1->pres_prev, st2->pres_prev, FALSE, ftol, abstol);
     }
-    state->nalloc = 0;
-    if (state->cg_gl)
+    cmp_int(stdout, "ngtc", -1, st1->ngtc, st2->ngtc);
+    cmp_int(stdout, "nhchainlength", -1, st1->nhchainlength, st2->nhchainlength);
+    if (st1->ngtc == st2->ngtc && st1->nhchainlength == st2->nhchainlength)
     {
-        sfree(state->cg_gl);
+        for (i = 0; i < st1->ngtc; i++)
+        {
+            nc = i*st1->nhchainlength;
+            for (j = 0; j < nc; j++)
+            {
+                cmp_real(stdout, "nosehoover_xi",
+                         i, st1->nosehoover_xi[nc+j], st2->nosehoover_xi[nc+j], ftol, abstol);
+            }
+        }
     }
-    state->cg_gl_nalloc = 0;
-    if (state->lambda)
+    cmp_int(stdout, "nnhpres", -1, st1->nnhpres, st2->nnhpres);
+    if (st1->nnhpres == st2->nnhpres && st1->nhchainlength == st2->nhchainlength)
     {
-        sfree(state->lambda);
+        for (i = 0; i < st1->nnhpres; i++)
+        {
+            nc = i*st1->nhchainlength;
+            for (j = 0; j < nc; j++)
+            {
+                cmp_real(stdout, "nosehoover_xi",
+                         i, st1->nhpres_xi[nc+j], st2->nhpres_xi[nc+j], ftol, abstol);
+            }
+        }
     }
-    if (state->ngtc > 0)
+
+    cmp_int(stdout, "natoms", -1, st1->natoms, st2->natoms);
+    if (st1->natoms == st2->natoms)
     {
-        sfree(state->nosehoover_xi);
-        sfree(state->nosehoover_vxi);
-        sfree(state->therm_integral);
+        if ((st1->flags & (1<<estX)) && (st2->flags & (1<<estX)))
+        {
+            fprintf(stdout, "comparing x\n");
+            cmp_rvecs(stdout, "x", st1->natoms, as_rvec_array(st1->x.data()), as_rvec_array(st2->x.data()), bRMSD, ftol, abstol);
+        }
+        if ((st1->flags & (1<<estV)) && (st2->flags & (1<<estV)))
+        {
+            fprintf(stdout, "comparing v\n");
+            cmp_rvecs(stdout, "v", st1->natoms, as_rvec_array(st1->v.data()), as_rvec_array(st2->v.data()), bRMSD, ftol, abstol);
+        }
     }
 }
 
-t_state *serial_init_local_state(t_state *state_global)
+rvec *getRvecArrayFromPaddedRVecVector(const PaddedRVecVector *v,
+                                       unsigned int            n)
 {
-    int      i;
-    t_state *state_local;
+    GMX_ASSERT(v->size() >= n, "We can't copy more elements than the vector size");
+
+    rvec *dest;
 
-    snew(state_local, 1);
+    snew(dest, n);
 
-    /* Copy all the contents */
-    *state_local = *state_global;
-    snew(state_local->lambda, efptNR);
-    /* local storage for lambda */
-    for (i = 0; i < efptNR; i++)
+    const rvec *vPtr = as_rvec_array(v->data());
+    for (unsigned int i = 0; i < n; i++)
     {
-        state_local->lambda[i] = state_global->lambda[i];
+        copy_rvec(vPtr[i], dest[i]);
     }
 
-    return state_local;
+    return dest;
 }
index 5d7b199640cdaca6b668655edd0efce10cd07dba..5b1ed2462798384cb49666e137c23fa1fdedd282 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 #ifndef GMX_MDTYPES_STATE_H
 #define GMX_MDTYPES_STATE_H
 
+#include <vector>
+
+#include "gromacs/math/paddedvector.h"
 #include "gromacs/math/vectypes.h"
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 
-struct energyhistory_t;
-
 /*
  * The t_state struct should contain all the (possibly) non-static
  * information required to define the state of the system.
@@ -89,17 +90,17 @@ typedef struct history_t
  */
 typedef struct ekinstate_t
 {
-    gmx_bool     bUpToDate;
-    int          ekin_n;
-    tensor      *ekinh;
-    tensor      *ekinf;
-    tensor      *ekinh_old;
-    tensor       ekin_total;
-    double      *ekinscalef_nhc;
-    double      *ekinscaleh_nhc;
-    double      *vscale_nhc;
-    real         dekindl;
-    real         mvcos;
+    gmx_bool             bUpToDate;
+    int                  ekin_n;
+    tensor              *ekinh;
+    tensor              *ekinf;
+    tensor              *ekinh_old;
+    tensor               ekin_total;
+    std::vector<double>  ekinscalef_nhc;
+    std::vector<double>  ekinscaleh_nhc;
+    std::vector<double>  vscale_nhc;
+    real                 dekindl;
+    real                 mvcos;
 } ekinstate_t;
 
 typedef struct df_history_t
@@ -199,39 +200,35 @@ typedef struct t_state
     int                     nhchainlength;   /* number of nose-hoover chains               */
     int                     flags;           /* Flags telling which entries are present      */
     int                     fep_state;       /* indicates which of the alchemical states we are in                 */
-    real                   *lambda;          /* lambda vector                               */
+    std::vector<real>       lambda;          /* lambda vector                               */
     matrix                  box;             /* box vector coordinates                         */
     matrix                  box_rel;         /* Relitaive box vectors to preserve shape        */
     matrix                  boxv;            /* box velocitites for Parrinello-Rahman pcoupl */
     matrix                  pres_prev;       /* Pressure of the previous step for pcoupl  */
     matrix                  svir_prev;       /* Shake virial for previous step for pcoupl */
     matrix                  fvir_prev;       /* Force virial of the previous step for pcoupl  */
-    double                 *nosehoover_xi;   /* for Nose-Hoover tcoupl (ngtc)       */
-    double                 *nosehoover_vxi;  /* for N-H tcoupl (ngtc)               */
-    double                 *nhpres_xi;       /* for Nose-Hoover pcoupl for barostat     */
-    double                 *nhpres_vxi;      /* for Nose-Hoover pcoupl for barostat     */
-    double                 *therm_integral;  /* for N-H/V-rescale tcoupl (ngtc)     */
+    std::vector<double>     nosehoover_xi;   /* for Nose-Hoover tcoupl (ngtc)       */
+    std::vector<double>     nosehoover_vxi;  /* for N-H tcoupl (ngtc)               */
+    std::vector<double>     nhpres_xi;       /* for Nose-Hoover pcoupl for barostat     */
+    std::vector<double>     nhpres_vxi;      /* for Nose-Hoover pcoupl for barostat     */
+    std::vector<double>     therm_integral;  /* for N-H/V-rescale tcoupl (ngtc)     */
     real                    veta;            /* trotter based isotropic P-coupling             */
     real                    vol0;            /* initial volume,required for computing NPT conserverd quantity */
-    int                     nalloc;          /* Allocation size for x and v when !=NULL*/
-    rvec                   *x;               /* the coordinates (natoms)                     */
-    rvec                   *v;               /* the velocities (natoms)                      */
-    rvec                   *cg_p;            /* p vector for conjugate gradient minimization */
-
-    history_t               hist;            /* Time history for restraints                  */
+    PaddedRVecVector        x;               /* the coordinates (natoms)                     */
+    PaddedRVecVector        v;               /* the velocities (natoms)                      */
+    PaddedRVecVector        cg_p;            /* p vector for conjugate gradient minimization */
 
     ekinstate_t             ekinstate;       /* The state of the kinetic energy data      */
 
-    struct energyhistory_t *enerhist;        /* Energy history for statistics           */
-    swapstate_t             swapstate;       /* Position swapping                       */
-    df_history_t            dfhist;          /*Free energy history for free energy analysis  */
-    edsamstate_t            edsamstate;      /* Essential dynamics / flooding history */
+    /* History for special algorithms, should be moved to a history struct */
+    history_t               hist;            /* Time history for restraints                  */
+    swapstate_t            *swapstate;       /* Position swapping                       */
+    df_history_t           *dfhist;          /*Free energy history for free energy analysis  */
+    edsamstate_t           *edsamstate;      /* Essential dynamics / flooding history */
 
     int                     ddp_count;       /* The DD partitioning count for this state  */
     int                     ddp_count_cg_gl; /* The DD part. count for index_gl     */
-    int                     ncg_gl;          /* The number of local charge groups            */
-    int                    *cg_gl;           /* The global cg number of the local cgs        */
-    int                     cg_gl_nalloc;    /* Allocation size of cg_gl;              */
+    std::vector<int>        cg_gl;           /* The global cg number of the local cgs        */
 } t_state;
 
 typedef struct t_extmass
@@ -255,10 +252,12 @@ typedef struct
 
 void init_gtc_state(t_state *state, int ngtc, int nnhpres, int nhchainlength);
 
-void init_state(t_state *state, int natoms, int ngtc, int nnhpres, int nhchainlength, int nlambda);
+void init_state(t_state *state, int natoms, int ngtc, int nnhpres, int nhchainlength, int dfhistNumLambda);
 
-t_state *serial_init_local_state(t_state *state_global);
+void comp_state(const t_state *st1, const t_state *st2, gmx_bool bRMSD, real ftol, real abstol);
 
-void done_state(t_state *state);
+/*! \brief Allocate an rvec pointer and copy the contents of v to it */
+rvec *getRvecArrayFromPaddedRVecVector(const PaddedRVecVector *v,
+                                       unsigned int            n);
 
 #endif
index e5f7212393d66871c6804010df9e76efa066ef30..2648150a59626b8727a697d77bab56ee3f8419d2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -229,7 +229,7 @@ void TextTableFormatter::addColumn(const char *title, int width, bool bWrap)
     {
         impl_->bPrintHeader_ = true;
     }
-    impl_->columns_.push_back(Impl::ColumnData(title, width, bWrap));
+    impl_->columns_.emplace_back(title, width, bWrap);
 }
 
 void TextTableFormatter::setFirstColumnIndent(int indent)
@@ -341,7 +341,7 @@ std::string TextTableFormatter::formatRow()
                 {
                     if (overflow > columnWidth && column->bWrap_)
                     {
-                        columnLines.push_back(std::string());
+                        columnLines.emplace_back();
                         continue;
                     }
                     columnWidth -= overflow;
index 2e5a578cb4ed2c8ea7729d6dabc07d6ad15984f2..5e7e3a7d9cc8281a435c4a0564cf4a56f1e01eab 100644 (file)
@@ -409,7 +409,7 @@ void HelpLinks::addLink(const std::string &linkName,
         default:
             GMX_RELEASE_ASSERT(false, "Output format not implemented for links");
     }
-    impl_->links_.push_back(Impl::LinkItem(linkName, replacement));
+    impl_->links_.emplace_back(linkName, replacement);
 }
 
 /********************************************************************
@@ -508,7 +508,7 @@ class HelpWriterContext::Impl
         void addReplacement(const std::string &search,
                             const std::string &replace)
         {
-            replacements_.push_back(ReplaceItem(search, replace));
+            replacements_.emplace_back(search, replace);
         }
 
         //! Replaces links in a given string.
index 0d7a3842f8700d6929a57b6e0589991395ec1e0b..1fb607a319ef12dbc849fa2a6b71a1a95844d14d 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2012,2014,2015, by the GROMACS development team, led by
+# Copyright (c) 2012,2014,2015,2016, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
 gmx_add_unit_test_object_library(onlinehelp-test-shared
                                  mock_helptopic.cpp)
 
-if (CMAKE_CXX_COMPILER_ID MATCHES "XL")
-    # This suppression stops a very verbose cascade of messages about the
-    # mocks, which is probably a compiler issue.
-    #   1540-2924 (W) Cannot pass an argument of non-POD class type "const gmx::HelpWriterContext" through ellipsis.
-    set_property(SOURCE mock_helptopic.cpp PROPERTY COMPILE_FLAGS "-qsuppress=1540-2924")
-endif()
-
 gmx_add_unit_test(OnlineHelpUnitTests onlinehelp-test
                   helpformat.cpp
                   helpmanager.cpp
index 62d006445c347feef7dba88995e2ca6ceabe13e2..172f357b55feabd68e28109c1e5a487fd3431a9d 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2010,2012,2013,2014,2015, by the GROMACS development team, led by
+# Copyright (c) 2010,2012,2013,2014,2015,2016, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
 # To help us fund GROMACS development, we humbly ask that you cite
 # the research papers on the package. Check out http://www.gromacs.org.
 
-file(GLOB OPTIONS_SOURCES *.cpp)
-set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${OPTIONS_SOURCES} PARENT_SCOPE)
+gmx_add_libgromacs_sources(
+    abstractoption.cpp
+    abstractsection.cpp
+    basicoptions.cpp
+    behaviorcollection.cpp
+    filenameoption.cpp
+    filenameoptionmanager.cpp
+    options.cpp
+    optionsassigner.cpp
+    optionsection.cpp
+    optionsvisitor.cpp
+    timeunitmanager.cpp
+    treesupport.cpp
+    )
 
 gmx_install_headers(
     abstractoption.h
+    abstractsection.h
     basicoptions.h
     filenameoption.h
     filenameoptionmanager.h
     ioptionsbehavior.h
     ioptionscontainer.h
+    ioptionscontainerwithsections.h
+    isectionstorage.h
+    ivaluestore.h
     optionfiletype.h
     optionflags.h
     options.h
+    optionsection.h
+    repeatingsection.h
     timeunitmanager.h
+    valuestore.h
     )
 
 if (BUILD_TESTING)
index 25d4ecab83908f7edc85c28bb40820dfcd61fe3f..1439837fdee251798c4a2bca175f8a57d8a9d63f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -47,6 +47,7 @@
 #include "gromacs/options/optionflags.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/variant.h"
 
 #include "basicoptionstorage.h"
 
@@ -116,14 +117,14 @@ void AbstractOptionStorage::startSet()
     bSetValuesHadErrors_ = false;
 }
 
-void AbstractOptionStorage::appendValue(const std::string &value)
+void AbstractOptionStorage::appendValue(const Variant &value)
 {
     GMX_RELEASE_ASSERT(bInSet_, "startSet() not called");
     try
     {
         convertValue(value);
     }
-    catch (...)
+    catch (const std::exception &)
     {
         bSetValuesHadErrors_ = true;
         throw;
@@ -260,19 +261,19 @@ std::string OptionInfo::formatDescription() const
     return description;
 }
 
-std::string OptionInfo::formatDefaultValueIfSet() const
+std::vector<Variant> OptionInfo::defaultValues() const
 {
-    return option().formatDefaultValueIfSet();
+    return option().defaultValues();
 }
 
-int OptionInfo::valueCount() const
+std::vector<std::string> OptionInfo::defaultValuesAsStrings() const
 {
-    return option().valueCount();
+    return option().defaultValuesAsStrings();
 }
 
-std::string OptionInfo::formatValue(int i) const
+std::vector<Variant> OptionInfo::normalizeValues(const std::vector<Variant> &values) const
 {
-    return option().formatValue(i);
+    return option().normalizeValues(values);
 }
 
 } // namespace gmx
index ff8a2596865374f82d1ba577d3ca34e934f16c09..d3f8050b6f00b5a73a676f2a4641a4892745cf20 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -66,10 +66,11 @@ namespace gmx
 class AbstractOptionStorage;
 template <typename T> class OptionStorageTemplate;
 class OptionManagerContainer;
+class Variant;
 
 namespace internal
 {
-class OptionsImpl;
+class OptionSectionImpl;
 }
 
 /*! \brief
@@ -198,7 +199,7 @@ class AbstractOption
          */
         friend class AbstractOptionStorage;
         //! Needed to be able to call createStorage().
-        friend class internal::OptionsImpl;
+        friend class internal::OptionSectionImpl;
 };
 
 /*! \brief
@@ -485,17 +486,38 @@ class OptionInfo
         std::string type() const;
         //! Returns the description of the option.
         std::string formatDescription() const;
+
         /*! \brief
-         * Returns the default value if set for the option as a string.
+         * Returns the default value(s) of the option.
+         *
+         * The returned values should all be of the same type, but returning
+         * each as a separate variant is currently simpler.
          *
-         * \see OptionTemplate::defaultValueIfSet()
+         * Currently, this can only be called before option values have been
+         * assigned.
          */
-        std::string formatDefaultValueIfSet() const;
-
-        //! Returns the number of values given for the option.
-        int valueCount() const;
-        //! Returns the i'th value of the option as a string.
-        std::string formatValue(int i) const;
+        std::vector<Variant> defaultValues() const;
+        /*! \brief
+         * Returns the default value(s) of the option as strings.
+         *
+         * If there is no default value, but defaultValueIfSet() is set, that
+         * is returned instead.
+         *
+         * Currently, this can only be called before option values have been
+         * assigned.
+         */
+        std::vector<std::string> defaultValuesAsStrings() const;
+        /*! \brief
+         * Converts given values to native representation for this option.
+         *
+         * For example, strings are parsed to the type that is actually used to
+         * store the options.
+         *
+         * The return value only depends on the option type, not on the current
+         * value of the option, and the current value in the option is not
+         * changed.
+         */
+        std::vector<Variant> normalizeValues(const std::vector<Variant> &values) const;
 
     protected:
         /*! \cond libapi */
index 55ea22fd261cb7219fe70c8f2b948bf05dace184..dd4e2eae764d2a4413f70d05794026bd2ec8724f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -44,6 +44,7 @@
 #define GMX_OPTIONS_ABSTRACTOPTIONSTORAGE_H
 
 #include <string>
+#include <vector>
 
 #include "gromacs/options/optionflags.h"
 #include "gromacs/utility/classhelpers.h"
@@ -54,6 +55,7 @@ namespace gmx
 class AbstractOption;
 class OptionInfo;
 class Options;
+class Variant;
 
 /*! \libinternal \brief
  * Abstract base class for converting, validating, and storing option values.
@@ -137,16 +139,12 @@ class AbstractOptionStorage
          * Returns the number of option values added so far.
          */
         virtual int valueCount() const = 0;
-        /*! \brief
-         * Returns the i'th value formatted as a string.
-         *
-         * If \p i is DefaultValueIfSetIndex, should format the default value
-         * if set (see OptionTemplate::defaultValueIfSet()).
-         */
-        virtual std::string formatValue(int i) const = 0;
-        //! \copydoc OptionInfo::formatDefaultValueIfSet()
-        std::string formatDefaultValueIfSet() const
-        { return formatValue(DefaultValueIfSetIndex); }
+        //! \copydoc OptionInfo::defaultValues()
+        virtual std::vector<Variant> defaultValues() const = 0;
+        //! \copydoc OptionInfo::defaultValuesAsStrings()
+        virtual std::vector<std::string> defaultValuesAsStrings() const = 0;
+        //! \copydoc OptionInfo::normalizeValues()
+        virtual std::vector<Variant> normalizeValues(const std::vector<Variant> &values) const = 0;
 
         /*! \brief
          * Starts adding values from a new source for the option.
@@ -171,16 +169,16 @@ class AbstractOptionStorage
          */
         void startSet();
         /*! \brief
-         * Adds a new value for the option, converting it from a string.
+         * Adds a new value for the option.
          *
-         * \param[in] value  String value to convert.
+         * \param[in] value  Value to convert.
          * \throws  InvalidInputError if value cannot be converted, or
          *      if there are too many values.
          *
          * This method should only be called between startSet() and
          * finishSet().
          */
-        void appendValue(const std::string &value);
+        void appendValue(const Variant &value);
         /*! \brief
          * Performs validation and/or actions once a set of values has been
          * added.
@@ -205,9 +203,6 @@ class AbstractOptionStorage
         void finish();
 
     protected:
-        //! Index used with formatValue() for formatting default value if set.
-        static const int DefaultValueIfSetIndex = -1;
-
         /*! \brief
          * Initializes the storage object from the settings object.
          *
@@ -270,9 +265,9 @@ class AbstractOptionStorage
          */
         virtual void clearSet() = 0;
         /*! \brief
-         * Adds a new value, converting it from a string.
+         * Adds a new value.
          *
-         * \param[in] value  String value to convert.
+         * \param[in] value  Value to convert.
          * \throws  InvalidInputError if \p value is not valid for this option
          *      or if there have been too many values in the set.
          *
@@ -281,7 +276,7 @@ class AbstractOptionStorage
          *
          * \see OptionStorageTemplate::convertValue()
          */
-        virtual void convertValue(const std::string &value) = 0;
+        virtual void convertValue(const Variant &value) = 0;
         /*! \brief
          * Performs validation and/or actions once a set of values has been
          * added.
diff --git a/src/gromacs/options/abstractsection.cpp b/src/gromacs/options/abstractsection.cpp
new file mode 100644 (file)
index 0000000..bb056cf
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Implements classes from abstractsection.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_options
+ */
+#include "gmxpre.h"
+
+#include "abstractsection.h"
+
+#include "options-impl.h"
+
+namespace gmx
+{
+
+/********************************************************************
+ * AbstractOptionSectionHandle
+ */
+
+// static
+IOptionSectionStorage *
+AbstractOptionSectionHandle::getStorage(internal::OptionSectionImpl *section)
+{
+    return section->storage_.get();
+}
+
+IOptionsContainer &AbstractOptionSectionHandle::addGroup()
+{
+    return section_->addGroup();
+}
+
+internal::OptionSectionImpl *
+AbstractOptionSectionHandle::addSectionImpl(const AbstractOptionSection &section)
+{
+    return section_->addSectionImpl(section);
+}
+
+OptionInfo *AbstractOptionSectionHandle::addOptionImpl(const AbstractOption &settings)
+{
+    return section_->addOptionImpl(settings);
+}
+
+/********************************************************************
+ * AbstractOptionSectionInfo
+ */
+
+const std::string &AbstractOptionSectionInfo::name() const
+{
+    return section_.name_;
+}
+
+} // namespace gmx
diff --git a/src/gromacs/options/abstractsection.h b/src/gromacs/options/abstractsection.h
new file mode 100644 (file)
index 0000000..ba54295
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \file
+ * \brief
+ * Declares base classes for declaring option sections.
+ *
+ * This header defines base classes for option section settings that are used
+ * with IOptionsContainerWithSections::addSection().  These classes implement
+ * the "named parameter" idiom for specifying section properties.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_ABSTRACTSECTION_H
+#define GMX_OPTIONS_ABSTRACTSECTION_H
+
+#include "gromacs/options/ioptionscontainerwithsections.h"
+#include "gromacs/options/isectionstorage.h"
+#include "gromacs/utility/classhelpers.h"
+#include "gromacs/utility/gmxassert.h"
+
+namespace gmx
+{
+
+class IOptionSectionStorage;
+
+namespace internal
+{
+class OptionSectionImpl;
+}
+
+/*! \brief
+ * Base class for specifying option section properties.
+ *
+ * \ingroup module_options
+ */
+class AbstractOptionSection
+{
+    protected:
+        //! \cond libapi
+        //! Initializes option properties with the given name.
+        explicit AbstractOptionSection(const char *name) : name_(name) {}
+
+        /*! \brief
+         * Creates a storage object corresponding to this section.
+         *
+         * Similar to AbstractOption::createStorage().
+         */
+        virtual IOptionSectionStorage *createStorage() const = 0;
+        //! \endcond
+
+    private:
+        const char *name_;
+
+        friend class internal::OptionSectionImpl;
+};
+
+/*! \brief
+ * Base class for handles to option sections.
+ *
+ * This class implements the common functionality for adding options and
+ * subsections to option sections.
+ *
+ * \ingroup module_options
+ */
+class AbstractOptionSectionHandle : public IOptionsContainerWithSections
+{
+    public:
+        // From IOptionsContainer
+        //! \copydoc IOptionsContainer::addGroup()
+        virtual IOptionsContainer &addGroup();
+
+    protected:
+        //! \cond libapi
+        /*! \brief
+         * Returns the storage for a particular type of section.
+         *
+         * This is intended for use in derived class constructors, where the
+         * handle needs access to the actual storage.  The handle should know
+         * the type of storage created for the section type it deals with, so
+         * the cast should always be successful.
+         */
+        template <typename StorageType>
+        static StorageType *getStorage(internal::OptionSectionImpl *section)
+        {
+            IOptionSectionStorage *storage = getStorage(section);
+            StorageType           *typedStorage
+                = dynamic_cast<StorageType *>(storage);
+            GMX_ASSERT(typedStorage != nullptr, "Mismatching section storage type");
+            return typedStorage;
+        }
+
+        //! Wraps a given section storage object.
+        explicit AbstractOptionSectionHandle(internal::OptionSectionImpl *section)
+            : section_(section)
+        {
+        }
+        //! \endcond
+
+    private:
+        // From IOptionsContainerWithSections
+        virtual internal::OptionSectionImpl *
+        addSectionImpl(const AbstractOptionSection &section);
+        // From IOptionsContainer
+        virtual OptionInfo *addOptionImpl(const AbstractOption &settings);
+
+        /*! \brief
+         * Implementation helper for the template method.
+         *
+         * This allows encapsulating the implementation within the source file.
+         */
+        static IOptionSectionStorage *getStorage(internal::OptionSectionImpl *section);
+
+        internal::OptionSectionImpl *section_;
+};
+
+class AbstractOptionSectionInfo
+{
+    public:
+        //! Wraps a given section storage object.
+        explicit AbstractOptionSectionInfo(internal::OptionSectionImpl *section)
+            : section_(*section)
+        {
+        }
+
+        //! Returns the name of the section.
+        const std::string &name() const;
+
+        //! Returns the wrapped section storage object.
+        internal::OptionSectionImpl       &section() { return section_; }
+        //! Returns the wrapped section storage object.
+        const internal::OptionSectionImpl &section() const { return section_; }
+
+    private:
+        internal::OptionSectionImpl &section_;
+
+        GMX_DISALLOW_COPY_AND_ASSIGN(AbstractOptionSectionInfo);
+};
+
+} // namespace gmx
+
+#endif
index 1a09d40569fbd53474e2d370ef55982a5956613f..4e2d83eb8c6246905453b3ca9543bcbda77f7f3f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -54,6 +54,7 @@
 
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/strconvert.h"
 #include "gromacs/utility/stringutil.h"
 
 #include "basicoptionstorage.h"
@@ -140,20 +141,9 @@ std::string BooleanOptionStorage::formatSingleValue(const bool &value) const
     return value ? "yes" : "no";
 }
 
-void BooleanOptionStorage::convertValue(const std::string &value)
+void BooleanOptionStorage::initConverter(ConverterType *converter)
 {
-    // TODO: Case-independence
-    if (value == "1" || value == "yes" || value == "true")
-    {
-        addValue(true);
-        return;
-    }
-    else if (value == "0" || value == "no" || value == "false")
-    {
-        addValue(false);
-        return;
-    }
-    GMX_THROW(InvalidInputError("Invalid value: '" + value + "'; supported values are: 1, 0, yes, no, true, false"));
+    converter->addConverter<std::string>(&fromStdString<bool>);
 }
 
 /********************************************************************
@@ -195,25 +185,9 @@ std::string IntegerOptionStorage::formatSingleValue(const int &value) const
     return formatString("%d", value);
 }
 
-void IntegerOptionStorage::convertValue(const std::string &value)
+void IntegerOptionStorage::initConverter(ConverterType *converter)
 {
-    const char *ptr = value.c_str();
-    char       *endptr;
-    errno = 0;
-    long int    ival = std::strtol(ptr, &endptr, 10);
-    if (errno == ERANGE
-        || ival < std::numeric_limits<int>::min()
-        || ival > std::numeric_limits<int>::max())
-    {
-        GMX_THROW(InvalidInputError("Invalid value: '" + value
-                                    + "'; it causes an integer overflow"));
-    }
-    if (*ptr == '\0' || *endptr != '\0')
-    {
-        GMX_THROW(InvalidInputError("Invalid value: '" + value
-                                    + "'; expected an integer"));
-    }
-    addValue(ival);
+    converter->addConverter<std::string>(&fromStdString<int>);
 }
 
 void IntegerOptionStorage::processSetValues(ValueList *values)
@@ -253,23 +227,9 @@ std::string Int64OptionStorage::formatSingleValue(const gmx_int64_t &value) cons
     return formatString("%" GMX_PRId64, value);
 }
 
-void Int64OptionStorage::convertValue(const std::string &value)
+void Int64OptionStorage::initConverter(ConverterType *converter)
 {
-    const char       *ptr = value.c_str();
-    char             *endptr;
-    errno = 0;
-    const gmx_int64_t ival = str_to_int64_t(ptr, &endptr);
-    if (errno == ERANGE)
-    {
-        GMX_THROW(InvalidInputError("Invalid value: '" + value
-                                    + "'; it causes an integer overflow"));
-    }
-    if (*ptr == '\0' || *endptr != '\0')
-    {
-        GMX_THROW(InvalidInputError("Invalid value: '" + value
-                                    + "'; expected an integer"));
-    }
-    addValue(ival);
+    converter->addConverter<std::string>(&fromStdString<gmx_int64_t>);
 }
 
 /********************************************************************
@@ -311,23 +271,16 @@ std::string DoubleOptionStorage::formatSingleValue(const double &value) const
     return formatString("%g", value / factor_);
 }
 
-void DoubleOptionStorage::convertValue(const std::string &value)
+void DoubleOptionStorage::initConverter(ConverterType *converter)
 {
-    const char *ptr = value.c_str();
-    char       *endptr;
-    errno = 0;
-    double      dval = std::strtod(ptr, &endptr);
-    if (errno == ERANGE)
-    {
-        GMX_THROW(InvalidInputError("Invalid value: '" + value
-                                    + "'; it causes an overflow/underflow"));
-    }
-    if (*ptr == '\0' || *endptr != '\0')
-    {
-        GMX_THROW(InvalidInputError("Invalid value: '" + value
-                                    + "'; expected a number"));
-    }
-    addValue(dval * factor_);
+    converter->addConverter<std::string>(&fromStdString<double>);
+    converter->addCastConversion<float>();
+}
+
+double DoubleOptionStorage::processValue(const double &value) const
+{
+    // TODO: Consider testing for overflow when scaling with factor_.
+    return value * factor_;
 }
 
 void DoubleOptionStorage::processSetValues(ValueList *values)
@@ -343,13 +296,11 @@ void DoubleOptionStorage::setScaleFactor(double factor)
     GMX_RELEASE_ASSERT(factor > 0.0, "Invalid scaling factor");
     if (!hasFlag(efOption_HasDefaultValue))
     {
-        double              scale = factor / factor_;
-        ValueList::iterator i;
-        for (i = values().begin(); i != values().end(); ++i)
+        double scale = factor / factor_;
+        for (double &value : values())
         {
-            (*i) *= scale;
+            value *= scale;
         }
-        refreshValues();
     }
     factor_ = factor;
 }
@@ -413,25 +364,16 @@ std::string FloatOptionStorage::formatSingleValue(const float &value) const
     return formatString("%g", value / factor_);
 }
 
-void FloatOptionStorage::convertValue(const std::string &value)
+void FloatOptionStorage::initConverter(ConverterType *converter)
 {
-    const char *ptr = value.c_str();
-    char       *endptr;
-    errno = 0;
-    double      dval = std::strtod(ptr, &endptr);
-    if (errno == ERANGE
-        || dval * factor_ < -std::numeric_limits<float>::max()
-        || dval * factor_ >  std::numeric_limits<float>::max())
-    {
-        GMX_THROW(InvalidInputError("Invalid value: '" + value
-                                    + "'; it causes an overflow/underflow"));
-    }
-    if (*ptr == '\0' || *endptr != '\0')
-    {
-        GMX_THROW(InvalidInputError("Invalid value: '" + value
-                                    + "'; expected a number"));
-    }
-    addValue(dval * factor_);
+    converter->addConverter<std::string>(&fromStdString<float>);
+    converter->addCastConversion<double>();
+}
+
+float FloatOptionStorage::processValue(const float &value) const
+{
+    // TODO: Consider testing for overflow when scaling with factor_.
+    return value * factor_;
 }
 
 void FloatOptionStorage::processSetValues(ValueList *values)
@@ -447,13 +389,11 @@ void FloatOptionStorage::setScaleFactor(double factor)
     GMX_RELEASE_ASSERT(factor > 0.0, "Invalid scaling factor");
     if (!hasFlag(efOption_HasDefaultValue))
     {
-        double              scale = factor / factor_;
-        ValueList::iterator i;
-        for (i = values().begin(); i != values().end(); ++i)
+        float scale = factor / factor_;
+        for (float &value : values())
         {
-            (*i) *= scale;
+            value *= scale;
         }
-        refreshValues();
     }
     factor_ = factor;
 }
@@ -526,7 +466,7 @@ StringOptionStorage::StringOptionStorage(const StringOption &settings)
             {
                 GMX_THROW(APIError("Enumeration value cannot be NULL"));
             }
-            allowed_.push_back(settings.enumValues_[i]);
+            allowed_.emplace_back(settings.enumValues_[i]);
         }
         if (settings.defaultEnumIndex_ >= 0)
         {
@@ -539,9 +479,7 @@ StringOptionStorage::StringOptionStorage(const StringOption &settings)
             {
                 GMX_THROW(APIError("Conflicting default values"));
             }
-            clear();
-            addValue(allowed_[settings.defaultEnumIndex_]);
-            commitValues();
+            setDefaultValue(allowed_[settings.defaultEnumIndex_]);
         }
     }
 }
@@ -562,17 +500,17 @@ std::string StringOptionStorage::formatSingleValue(const std::string &value) con
     return value;
 }
 
-void StringOptionStorage::convertValue(const std::string &value)
+void StringOptionStorage::initConverter(ConverterType * /*converter*/)
 {
-    if (allowed_.size() == 0)
-    {
-        addValue(value);
-    }
-    else
+}
+
+std::string StringOptionStorage::processValue(const std::string &value) const
+{
+    if (allowed_.size() > 0)
     {
-        ValueList::const_iterator match = findEnumValue(allowed_, value);
-        addValue(*match);
+        return *findEnumValue(this->allowed_, value);
     }
+    return value;
 }
 
 /********************************************************************
@@ -617,8 +555,8 @@ StringOption::createStorage(const OptionManagerContainer & /*managers*/) const
 EnumOptionStorage::EnumOptionStorage(const AbstractOption &settings,
                                      const char *const *enumValues, int count,
                                      int defaultValue, int defaultValueIfSet,
-                                     EnumIndexStorePointer store)
-    : MyBase(settings), info_(this), store_(move(store))
+                                     StorePointer store)
+    : MyBase(settings, std::move(store)), info_(this)
 {
     if (enumValues == NULL)
     {
@@ -639,7 +577,7 @@ EnumOptionStorage::EnumOptionStorage(const AbstractOption &settings,
         {
             GMX_THROW(APIError("Enumeration value cannot be NULL"));
         }
-        allowed_.push_back(enumValues[i]);
+        allowed_.emplace_back(enumValues[i]);
     }
 
     GMX_ASSERT(defaultValue < count, "Default enumeration value is out of range");
@@ -653,12 +591,6 @@ EnumOptionStorage::EnumOptionStorage(const AbstractOption &settings,
     {
         setDefaultValueIfSet(defaultValueIfSet);
     }
-
-    if (values().empty())
-    {
-        values() = store_->initialValues();
-    }
-    refreshEnumIndexStore();
 }
 
 std::string EnumOptionStorage::formatExtraDescription() const
@@ -678,28 +610,13 @@ std::string EnumOptionStorage::formatSingleValue(const int &value) const
     return allowed_[value];
 }
 
-void EnumOptionStorage::convertValue(const std::string &value)
-{
-    std::vector<std::string>::const_iterator match = findEnumValue(allowed_, value);
-    addValue(match - allowed_.begin());
-}
-
-void EnumOptionStorage::processSetValues(ValueList *values)
-{
-    const size_t newSize = (hasFlag(efOption_ClearOnNextSet) ? 0 : valueCount())
-        + std::max<size_t>(values->size(), 1);
-    store_->reserveSpace(newSize);
-}
-
-void EnumOptionStorage::refreshValues()
-{
-    MyBase::refreshValues();
-    refreshEnumIndexStore();
-}
-
-void EnumOptionStorage::refreshEnumIndexStore()
+void EnumOptionStorage::initConverter(ConverterType *converter)
 {
-    store_->refreshValues(values());
+    converter->addConverter<std::string>(
+            [this] (const std::string &value)
+            {
+                return findEnumValue(this->allowed_, value) - this->allowed_.begin();
+            });
 }
 
 /********************************************************************
@@ -728,18 +645,14 @@ const std::vector<std::string> &EnumOptionInfo::allowedValues() const
 namespace internal
 {
 
-EnumIndexStoreInterface::~EnumIndexStoreInterface()
-{
-}
-
 //! \cond internal
 AbstractOptionStorage *
 createEnumOptionStorage(const AbstractOption &option,
                         const char *const *enumValues, int count,
                         int defaultValue, int defaultValueIfSet,
-                        EnumIndexStoreInterface *store)
+                        IOptionValueStore<int> *store)
 {
-    EnumOptionStorage::EnumIndexStorePointer storePtr(store);
+    std::unique_ptr<IOptionValueStore<int> > storePtr(store);
     return new EnumOptionStorage(option, enumValues, count, defaultValue,
                                  defaultValueIfSet, move(storePtr));
 }
index 257cf5100eb14f55ecbaa36c6fa888826001378c..0976f2bcb477e134a3bfa123d69025ce58df7629 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -50,6 +50,8 @@
 #include <vector>
 
 #include "gromacs/options/abstractoption.h"
+#include "gromacs/options/ivaluestore.h"
+#include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/gmxassert.h"
 
@@ -376,97 +378,72 @@ namespace internal
 
 /*! \internal
  * \brief
- * Interface for handling storage of the enum indexes.
- *
- * This interface acts as a proxy between the EnumOptionStorage class (that
- * operates on `int` values), and the actual enum variable that receives the
- * values.  The implementation of this interface takes care of conversion of
- * the values and writing them out into the actual enum variables.
- *
- * \ingroup module_options
- */
-class EnumIndexStoreInterface
-{
-    public:
-        virtual ~EnumIndexStoreInterface();
-
-        //! Returns initial values from the actual enum variables.
-        virtual std::vector<int> initialValues() const = 0;
-        //! Reserves space for storage in the actual enum variables.
-        virtual void reserveSpace(size_t count) = 0;
-        //! Updates values in the actual enum variables based on option values.
-        virtual void refreshValues(const std::vector<int> &values) = 0;
-};
-
-/*! \internal
- * \brief
- * Type-specific implementation for EnumIndexStoreInterface.
+ * Type-specific implementation for IOptionValueStore for an enum option.
  *
  * This class is instantiated for each enum type for which EnumOption is used,
- * and takes care of managing the `int`-to-`enum` conversions as described in
- * EnumIndexStoreInterface.  Having this as a template in the header allows the
- * actual storage implementation to not be in the header, which would require
- * exposing all the internals through this one header...
+ * and takes care of managing `int`-to-`enum` conversions.  Having this part in
+ * the header allows the actual storage implementation to not be in the header,
+ * which would require exposing all the internals through this one header...
  *
  * \ingroup module_options
  */
 template <typename EnumType>
-class EnumIndexStore : public EnumIndexStoreInterface
+class EnumIndexStore : public IOptionValueStore<int>
 {
     public:
         //! Initializes the storage for the given actual enum variables.
         EnumIndexStore(EnumType *store, std::vector<EnumType> *storeVector)
             : store_(store), storeVector_(storeVector)
         {
-        }
-
-        virtual std::vector<int> initialValues() const
-        {
-            std::vector<int> result;
-            if (storeVector_ != NULL)
+            if (storeVector_ != nullptr)
             {
-                typename std::vector<EnumType>::const_iterator i;
-                for (i = storeVector_->begin(); i != storeVector_->end(); ++i)
+                for (EnumType value : *storeVector_)
                 {
-                    result.push_back(*i);
+                    intStore_.push_back(static_cast<int>(value));
                 }
             }
-            else if (store_ != NULL)
+            else if (store_ != nullptr)
             {
                 // TODO: Copy more than one value if that would make sense.
-                result.push_back(store_[0]);
+                intStore_.push_back(static_cast<int>(store_[0]));
             }
-            return result;
         }
-        virtual void reserveSpace(size_t count)
+
+        virtual int valueCount() { return static_cast<int>(intStore_.size()); }
+        virtual ArrayRef<int> values() { return intStore_; }
+        virtual void clear()
         {
-            if (storeVector_ != NULL)
+            intStore_.clear();
+            if (storeVector_ != nullptr)
             {
-                storeVector_->reserve(count);
+                storeVector_->clear();
             }
         }
-        virtual void refreshValues(const std::vector<int> &values)
+        virtual void reserve(size_t count)
         {
-            if (store_ != NULL)
+            intStore_.reserve(intStore_.size() + count);
+            if (storeVector_ != nullptr)
             {
-                for (size_t i = 0; i < values.size(); ++i)
-                {
-                    store_[i] = static_cast<EnumType>(values[i]);
-                }
+                storeVector_->reserve(storeVector_->size() + count);
             }
-            if (storeVector_ != NULL)
+        }
+        virtual void append(const int &value)
+        {
+            const size_t count = intStore_.size();
+            intStore_.push_back(value);
+            if (store_ != nullptr)
             {
-                GMX_ASSERT(storeVector_->capacity() >= values.size(),
-                           "reserveSpace() should have been called earlier");
-                storeVector_->resize(values.size());
-                for (size_t i = 0; i < values.size(); ++i)
-                {
-                    (*storeVector_)[i] = static_cast<EnumType>(values[i]);
-                }
+                store_[count] = static_cast<EnumType>(value);
+            }
+            if (storeVector_ != nullptr)
+            {
+                storeVector_->push_back(static_cast<EnumType>(value));
             }
         }
 
     private:
+        //! Stores the integer values for values().
+        std::vector<int>       intStore_;
         EnumType              *store_;
         std::vector<EnumType> *storeVector_;
 };
@@ -486,7 +463,7 @@ AbstractOptionStorage *
 createEnumOptionStorage(const AbstractOption &option,
                         const char *const *enumValues, int count,
                         int defaultValue, int defaultValueIfSet,
-                        EnumIndexStoreInterface *store);
+                        IOptionValueStore<int> *store);
 //! \endcond
 
 }   // namespace internal
index a4aa6ead9f3c448bf6e9ac86f786dd171d4b5f21..92aefa31fa6065a0b0693fb59a1ec797a97b412d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -59,7 +59,7 @@ namespace gmx
 /*! \internal \brief
  * Converts, validates, and stores boolean values.
  */
-class BooleanOptionStorage : public OptionStorageTemplate<bool>
+class BooleanOptionStorage : public OptionStorageTemplateSimple<bool>
 {
     public:
         /*! \brief
@@ -80,7 +80,7 @@ class BooleanOptionStorage : public OptionStorageTemplate<bool>
         bool defaultValue() const { return valueCount() > 0 && values()[0]; }
 
     private:
-        virtual void convertValue(const std::string &value);
+        virtual void initConverter(ConverterType *converter);
 
         BooleanOptionInfo       info_;
 };
@@ -88,7 +88,7 @@ class BooleanOptionStorage : public OptionStorageTemplate<bool>
 /*! \internal \brief
  * Converts, validates, and stores integer values.
  */
-class IntegerOptionStorage : public OptionStorageTemplate<int>
+class IntegerOptionStorage : public OptionStorageTemplateSimple<int>
 {
     public:
         //! \copydoc BooleanOptionStorage::BooleanOptionStorage()
@@ -103,7 +103,7 @@ class IntegerOptionStorage : public OptionStorageTemplate<int>
         virtual std::string formatSingleValue(const int &value) const;
 
     private:
-        virtual void convertValue(const std::string &value);
+        virtual void initConverter(ConverterType *converter);
         virtual void processSetValues(ValueList *values);
 
         IntegerOptionInfo       info_;
@@ -112,7 +112,7 @@ class IntegerOptionStorage : public OptionStorageTemplate<int>
 /*! \internal \brief
  * Converts, validates, and stores integer values.
  */
-class Int64OptionStorage : public OptionStorageTemplate<gmx_int64_t>
+class Int64OptionStorage : public OptionStorageTemplateSimple<gmx_int64_t>
 {
     public:
         //! \copydoc BooleanOptionStorage::BooleanOptionStorage()
@@ -126,7 +126,7 @@ class Int64OptionStorage : public OptionStorageTemplate<gmx_int64_t>
         virtual std::string formatSingleValue(const gmx_int64_t &value) const;
 
     private:
-        virtual void convertValue(const std::string &value);
+        virtual void initConverter(ConverterType *converter);
 
         Int64OptionInfo       info_;
 };
@@ -134,7 +134,7 @@ class Int64OptionStorage : public OptionStorageTemplate<gmx_int64_t>
 /*! \internal \brief
  * Converts, validates, and stores floating-point (double) values.
  */
-class DoubleOptionStorage : public OptionStorageTemplate<double>
+class DoubleOptionStorage : public OptionStorageTemplateSimple<double>
 {
     public:
         //! \copydoc IntegerOptionStorage::IntegerOptionStorage()
@@ -150,7 +150,8 @@ class DoubleOptionStorage : public OptionStorageTemplate<double>
         void setScaleFactor(double factor);
 
     private:
-        virtual void convertValue(const std::string &value);
+        virtual void initConverter(ConverterType *converter);
+        virtual double processValue(const double &value) const;
         virtual void processSetValues(ValueList *values);
 
         DoubleOptionInfo        info_;
@@ -161,7 +162,7 @@ class DoubleOptionStorage : public OptionStorageTemplate<double>
 /*! \internal \brief
  * Converts, validates, and stores floating-point (float) values.
  */
-class FloatOptionStorage : public OptionStorageTemplate<float>
+class FloatOptionStorage : public OptionStorageTemplateSimple<float>
 {
     public:
         //! \copydoc IntegerOptionStorage::IntegerOptionStorage()
@@ -177,7 +178,8 @@ class FloatOptionStorage : public OptionStorageTemplate<float>
         void setScaleFactor(double factor);
 
     private:
-        virtual void convertValue(const std::string &value);
+        virtual void initConverter(ConverterType *converter);
+        virtual float processValue(const float &value) const;
         virtual void processSetValues(ValueList *values);
 
         FloatOptionInfo         info_;
@@ -188,7 +190,7 @@ class FloatOptionStorage : public OptionStorageTemplate<float>
 /*! \internal \brief
  * Converts, validates, and stores string values.
  */
-class StringOptionStorage : public OptionStorageTemplate<std::string>
+class StringOptionStorage : public OptionStorageTemplateSimple<std::string>
 {
     public:
         //! \copydoc DoubleOptionStorage::DoubleOptionStorage()
@@ -204,7 +206,8 @@ class StringOptionStorage : public OptionStorageTemplate<std::string>
         const ValueList &allowedValues() const { return allowed_; }
 
     private:
-        virtual void convertValue(const std::string &value);
+        virtual void initConverter(ConverterType *converter);
+        virtual std::string processValue(const std::string &value) const;
 
         StringOptionInfo        info_;
         ValueList               allowed_;
@@ -213,13 +216,9 @@ class StringOptionStorage : public OptionStorageTemplate<std::string>
 /*! \internal \brief
  * Converts, validates, and stores enum values.
  */
-class EnumOptionStorage : public OptionStorageTemplate<int>
+class EnumOptionStorage : public OptionStorageTemplateSimple<int>
 {
     public:
-        //! Shorthand for the enum index storage interface.
-        typedef std::unique_ptr<internal::EnumIndexStoreInterface>
-            EnumIndexStorePointer;
-
         /*! \brief
          * Initializes the storage from option settings.
          *
@@ -239,7 +238,7 @@ class EnumOptionStorage : public OptionStorageTemplate<int>
         EnumOptionStorage(const AbstractOption &settings,
                           const char *const *enumValues, int count,
                           int defaultValue, int defaultValueIfSet,
-                          EnumIndexStorePointer store);
+                          StorePointer store);
 
         virtual OptionInfo &optionInfo() { return info_; }
         virtual std::string typeString() const { return "enum"; }
@@ -250,15 +249,10 @@ class EnumOptionStorage : public OptionStorageTemplate<int>
         const std::vector<std::string> &allowedValues() const { return allowed_; }
 
     private:
-        virtual void convertValue(const std::string &value);
-        virtual void processSetValues(ValueList *values);
-        virtual void refreshValues();
-
-        void refreshEnumIndexStore();
+        virtual void initConverter(ConverterType *converter);
 
         EnumOptionInfo            info_;
         std::vector<std::string>  allowed_;
-        EnumIndexStorePointer     store_;
 };
 
 /*!\}*/
index b793a934b50dc862e7556c0a360efa34b5dd6d05..746ea5d2f8ae63930a34377c1cb8401c6f0cb113 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -313,7 +313,11 @@ std::string FileNameOptionStorage::formatSingleValue(const std::string &value) c
     return value;
 }
 
-void FileNameOptionStorage::convertValue(const std::string &value)
+void FileNameOptionStorage::initConverter(ConverterType * /*converter*/)
+{
+}
+
+std::string FileNameOptionStorage::processValue(const std::string &value) const
 {
     if (manager_ != NULL)
     {
@@ -340,8 +344,7 @@ void FileNameOptionStorage::convertValue(const std::string &value)
                                "Manager returned an invalid file name");
                 }
             }
-            addValue(processedValue);
-            return;
+            return processedValue;
         }
     }
     // Currently, directory options are simple, and don't need any
@@ -349,8 +352,7 @@ void FileNameOptionStorage::convertValue(const std::string &value)
     // TODO: Consider splitting them into a separate DirectoryOption.
     if (isDirectoryOption())
     {
-        addValue(value);
-        return;
+        return value;
     }
     const int fileType = fn2ftp(value.c_str());
     if (fileType == efNR)
@@ -370,14 +372,14 @@ void FileNameOptionStorage::convertValue(const std::string &value)
                            value.c_str(), joinStrings(extensions(), ", ").c_str());
         GMX_THROW(InvalidInputError(message));
     }
-    addValue(value);
+    return value;
 }
 
 void FileNameOptionStorage::processAll()
 {
     if (manager_ != NULL && hasFlag(efOption_HasDefaultValue))
     {
-        ValueList &valueList = values();
+        ArrayRef<std::string> valueList = values();
         GMX_RELEASE_ASSERT(valueList.size() == 1,
                            "There should be only one default value");
         if (!valueList[0].empty())
@@ -394,7 +396,6 @@ void FileNameOptionStorage::processAll()
                 GMX_ASSERT(isValidType(fn2ftp(newValue.c_str())),
                            "Manager returned an invalid default value");
                 valueList[0] = newValue;
-                refreshValues();
             }
         }
     }
index 8e799687dd4e2de2157a5032fa8af7c7f96c6016..97fda90324b99ce8d9adb8780d0acf496fa3cba9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -58,7 +58,7 @@ class FileNameOptionManager;
 /*! \internal \brief
  * Converts, validates, and stores file names.
  */
-class FileNameOptionStorage : public OptionStorageTemplate<std::string>
+class FileNameOptionStorage : public OptionStorageTemplateSimple<std::string>
 {
     public:
         /*! \brief
@@ -100,7 +100,8 @@ class FileNameOptionStorage : public OptionStorageTemplate<std::string>
         ConstArrayRef<int> fileTypes() const;
 
     private:
-        virtual void convertValue(const std::string &value);
+        virtual void initConverter(ConverterType *converter);
+        virtual std::string processValue(const std::string &value) const;
         virtual void processAll();
 
         FileNameOptionInfo      info_;
index 0cc29291c91d5ce5c99ce881e535272e2d6d8400..3cdaafc0210a4253255816dcf63301ff4401be8a 100644 (file)
@@ -92,18 +92,6 @@ class IOptionsContainer
          * output.
          */
         virtual IOptionsContainer &addGroup() = 0;
-        /*! \brief
-         * Adds a recognized option.
-         *
-         * \param[in] settings Option description.
-         * \returns   OptionInfo object for the created option (never NULL).
-         * \throws    APIError if invalid option settings are provided.
-         *
-         * This method provides the internal implementation, but in most cases
-         * the templated method is called from user code.
-         * See the templated method for more details.
-         */
-        virtual OptionInfo *addOption(const AbstractOption &settings) = 0;
         /*! \brief
          * Adds a recognized option.
          *
@@ -130,7 +118,7 @@ class IOptionsContainer
         typename OptionType::InfoType *addOption(const OptionType &settings)
         {
             OptionInfo *info
-                = addOption(static_cast<const AbstractOption &>(settings));
+                = addOptionImpl(static_cast<const AbstractOption &>(settings));
             GMX_ASSERT(info->isType<typename OptionType::InfoType>(),
                        "Mismatching option info type declaration and implementation");
             return info->toType<typename OptionType::InfoType>();
@@ -141,6 +129,19 @@ class IOptionsContainer
         // (no need for the virtual, but some compilers warn otherwise)
         virtual ~IOptionsContainer();
 
+        /*! \brief
+         * Adds a recognized option.
+         *
+         * \param[in] settings Option description.
+         * \returns   OptionInfo object for the created option (never NULL).
+         * \throws    APIError if invalid option settings are provided.
+         *
+         * This method provides the internal implementation, but the templated
+         * method is called from user code.  See the templated method for more
+         * details.
+         */
+        virtual OptionInfo *addOptionImpl(const AbstractOption &settings) = 0;
+
         GMX_DEFAULT_CONSTRUCTORS(IOptionsContainer);
 };
 
diff --git a/src/gromacs/options/ioptionscontainerwithsections.h b/src/gromacs/options/ioptionscontainerwithsections.h
new file mode 100644 (file)
index 0000000..198e0ca
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \file
+ * \brief
+ * Declares gmx::IOptionsContainerWithSections.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inpublicapi
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_IOPTIONSCONTAINERWITHSECTIONS_H
+#define GMX_OPTIONS_IOPTIONSCONTAINERWITHSECTIONS_H
+
+#include "gromacs/options/ioptionscontainer.h"
+
+namespace gmx
+{
+
+class AbstractOptionSection;
+class AbstractOptionSectionHandle;
+
+namespace internal
+{
+class OptionSectionImpl;
+}
+
+/*! \brief
+ * Interface for adding input options with sections.
+ *
+ * This interface extends IOptionsContainer with an additional addSection()
+ * method that supports creating a hierarchy of sections for the options.
+ *
+ * Header optionsection.h provides OptionSection.
+ *
+ * \inpublicapi
+ * \ingroup module_options
+ */
+class IOptionsContainerWithSections : public IOptionsContainer
+{
+    public:
+        /*! \brief
+         * Adds a section to this collection.
+         *
+         * \tparam    SectionType Type of the section description object.
+         * \param[in] section     Section description.
+         * \returns   AbstractOptionSectionHandle object for the created option.
+         * \throws    APIError if invalid option settings are provided.
+         *
+         * Options can be added to the section through the returned handle.
+         *
+         * \internal
+         * \p SectionType::HandleType must specify a type that derives from
+         * AbstractinOptionSectionHandle and has a suitable constructor.
+         */
+        template <class SectionType>
+        typename SectionType::HandleType addSection(const SectionType &section)
+        {
+            internal::OptionSectionImpl *storage
+                = addSectionImpl(static_cast<const AbstractOptionSection &>(section));
+            return typename SectionType::HandleType(storage);
+        }
+
+    protected:
+        // Disallow deletion through the interface.
+        // (no need for the virtual, but some compilers warn otherwise)
+        virtual ~IOptionsContainerWithSections();
+
+        /*! \brief
+         * Adds a section to this container.
+         *
+         * \param[in] section     Section description.
+         * \returns   Pointer to the internal section representation object.
+         */
+        virtual internal::OptionSectionImpl *
+        addSectionImpl(const AbstractOptionSection &section) = 0;
+
+        GMX_DEFAULT_CONSTRUCTORS(IOptionsContainerWithSections);
+};
+
+} // namespace
+
+#endif
diff --git a/src/gromacs/options/isectionstorage.h b/src/gromacs/options/isectionstorage.h
new file mode 100644 (file)
index 0000000..f2a8073
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \file
+ * \brief
+ * Declares gmx::IOptionSectionStorage.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_ISECTIONSTORAGE_H
+#define GMX_OPTIONS_ISECTIONSTORAGE_H
+
+namespace gmx
+{
+
+/*! \internal
+ * \brief
+ * Provides behavior specific to a certain option section type.
+ *
+ * \ingroup module_options
+ */
+class IOptionSectionStorage
+{
+    public:
+        virtual ~IOptionSectionStorage();
+
+        /*! \brief
+         * Called once before the first call to startSection().
+         *
+         * This is called once all options have been added to the section.
+         * The current implementation does not call this if startSection() is
+         * never called.
+         */
+        virtual void initStorage() = 0;
+        /*! \brief
+         * Called when option assignment enters this section.
+         */
+        virtual void startSection()  = 0;
+        /*! \brief
+         * Called when option assignment leaves this section.
+         */
+        virtual void finishSection() = 0;
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/options/ivaluestore.h b/src/gromacs/options/ivaluestore.h
new file mode 100644 (file)
index 0000000..3476529
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \file
+ * \brief
+ * Declares gmx::IOptionValueStore.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_IVALUESTORE_H
+#define GMX_OPTIONS_IVALUESTORE_H
+
+namespace gmx
+{
+
+template <typename T> class ArrayRef;
+
+/*! \internal
+ * \brief
+ * Represents the final storage location of option values.
+ *
+ * \todo
+ * Try to make this more like a write-only interface, getting rid of the need
+ * to access the stored values through this interface.  That would simplify
+ * things.
+ *
+ * \ingroup module_options
+ */
+template <typename T>
+class IOptionValueStore
+{
+    public:
+        virtual ~IOptionValueStore() {}
+
+        //! Returns the number of values stored so far.
+        virtual int valueCount() = 0;
+        //! Returns a reference to the actual values.
+        virtual ArrayRef<T> values() = 0;
+        //! Removes all stored values.
+        virtual void clear() = 0;
+        //! Reserves memory for additional `count` entries.
+        virtual void reserve(size_t count) = 0;
+        //! Appends a value to the store.
+        virtual void append(const T &value) = 0;
+};
+
+} // namespace gmx
+
+#endif
index e17a77617a77ddc015e2d07e7d54a8e6ca8287c6..d06ffb48d30a29c84e942f863a9a96f640cf7595 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 #include <vector>
 
 #include "gromacs/options/abstractoption.h"
+#include "gromacs/options/abstractoptionstorage.h"
+#include "gromacs/options/ioptionscontainer.h"
+#include "gromacs/options/ioptionscontainerwithsections.h"
+#include "gromacs/options/isectionstorage.h"
 #include "gromacs/options/optionmanagercontainer.h"
 #include "gromacs/options/options.h"
+#include "gromacs/options/optionsection.h"
 
 namespace gmx
 {
 
-class AbstractOptionStorage;
-
 namespace internal
 {
 
 /*! \internal
  * \brief
- * Private implementation class for Options.
+ * Internal implementation class for storing an option section.
  *
- * Note that in addition to Options, the OptionsAssigner and OptionsIterator
- * classes also directly access this class.
+ * All options are stored within a section: the top-level contents of an
+ * Options object are handled within an unnamed, "root" section.
+ * This class handles the common functionality for all sections, related to
+ * storing the options and subsections.  Functionality specific to a section
+ * type is provided by IOptionSectionStorage.
  *
  * \ingroup module_options
  */
-class OptionsImpl
+class OptionSectionImpl : public IOptionsContainerWithSections
 {
     public:
         /*! \internal \brief
@@ -86,35 +92,55 @@ class OptionsImpl
                 typedef std::list<Group> SubgroupList;
 
                 //! Creates a group within the given Options.
-                explicit Group(OptionsImpl *parent) : parent_(parent) {}
+                explicit Group(OptionSectionImpl *parent) : parent_(parent) {}
 
                 // From IOptionsContainer
                 virtual IOptionsContainer &addGroup();
-                virtual OptionInfo *addOption(const AbstractOption &settings);
+                virtual OptionInfo *addOptionImpl(const AbstractOption &settings);
 
                 //! Containing options object.
-                OptionsImpl  *parent_;
+                OptionSectionImpl  *parent_;
                 /*! \brief
                  * List of options, in insertion order.
                  *
                  * Pointers in this container point to the objects managed by
                  * Impl::optionsMap_.
                  */
-                OptionList    options_;
+                OptionList          options_;
                 //! List of groups, in insertion order.
-                SubgroupList  subgroups_;
+                SubgroupList        subgroups_;
         };
 
         //! Smart pointer for managing an AbstractOptionStorage object.
         typedef std::unique_ptr<AbstractOptionStorage>
             AbstractOptionStoragePointer;
-        //! Convenience type for list of sections.
-        typedef std::vector<Options *> SubSectionList;
         //! Convenience typedef for a map that contains all the options.
         typedef std::map<std::string, AbstractOptionStoragePointer> OptionMap;
+        //! Smart pointer for managing subsections.
+        typedef std::unique_ptr<OptionSectionImpl> SectionPointer;
+        //! Convenience typedef for a container for subsections.
+        typedef std::vector<SectionPointer> SectionList;
+
+        //! Creates storage for a new section.
+        OptionSectionImpl(const OptionManagerContainer          &managers,
+                          std::unique_ptr<IOptionSectionStorage> storage,
+                          const char                            *name)
+            : managers_(managers), storage_(std::move(storage)), info_(this),
+              name_(name), rootGroup_(this), storageInitialized_(false)
+        {
+        }
 
-        //! Sets the name and title.
-        OptionsImpl(const char *name, const char *title);
+        // From IOptionsContainerWithSections
+        virtual OptionSectionImpl *addSectionImpl(const AbstractOptionSection &section);
+
+        // From IOptionsContainer
+        virtual IOptionsContainer &addGroup();
+        virtual OptionInfo *addOptionImpl(const AbstractOption &settings);
+
+        //! Returns section info object for this section.
+        OptionSectionInfo       &info() { return info_; }
+        //! Returns section info object for this section.
+        const OptionSectionInfo &info() const { return info_; }
 
         /*! \brief
          * Finds a subsection by name.
@@ -124,7 +150,7 @@ class OptionsImpl
          *
          * Does not throw.
          */
-        Options *findSubSection(const char *name) const;
+        OptionSectionImpl *findSection(const char *name) const;
         /*! \brief
          * Finds an option by name.
          *
@@ -136,38 +162,58 @@ class OptionsImpl
         AbstractOptionStorage *findOption(const char *name) const;
 
         /*! \brief
-         * Calls AbstractOptionStorage::startSource() for all options,
-         * including subsections.
+         * Called when entering the section.
          *
-         * Does not throw.
+         * Calls AbstractOptionStorage::startSource() for all options.
          */
-        void startSource();
-
-        //! Name for the Options object.
-        std::string             name_;
+        void start();
         /*! \brief
-         * Option managers set for this collection.
-         *
-         * This is non-empty only for the top-level Options object.
+         * Calls AbstractOptionStorage::finish() for all options.
          */
-        OptionManagerContainer  managers_;
+        void finish();
+
+        //! Reference to the option managers in the parent Options object.
+        const OptionManagerContainer           &managers_;
+        //! Type-specific storage object for this section.
+        std::unique_ptr<IOptionSectionStorage>  storage_;
+        //! Info object for this section.
+        OptionSectionInfo                       info_;
+        //! Name of this section (empty and unused for the root section).
+        std::string                             name_;
         /*! \brief
          * Group that contains all options (and subgroups).
          *
          * This is used to store the insertion order of options.
          */
-        Group                   rootGroup_;
+        Group                          rootGroup_;
         //! Map from option names to options; owns the option storage objects.
-        OptionMap               optionMap_;
-        /*! \brief
-         * List of subsections, in insertion order.
-         *
-         * This container contains only references to external objects; memory
-         * management is performed elsewhere.
-         */
-        SubSectionList          subSections_;
-        //! Options object that contains this object as a subsection, or NULL.
-        Options                *parent_;
+        OptionMap                      optionMap_;
+        //! List of subsections, in insertion order.
+        SectionList                    subsections_;
+        //! Whether initStorage() has been called for `storage_`.
+        bool                           storageInitialized_;
+
+        GMX_DISALLOW_COPY_AND_ASSIGN(OptionSectionImpl);
+};
+
+/*! \internal
+ * \brief
+ * Private implementation class for Options.
+ *
+ * Note that in addition to Options, the OptionsAssigner class also directly
+ * accesses this class.
+ *
+ * \ingroup module_options
+ */
+class OptionsImpl
+{
+    public:
+        OptionsImpl();
+
+        //! Option managers set for this collection.
+        OptionManagerContainer  managers_;
+        //! Root section for this collection.
+        OptionSectionImpl       rootSection_;
 };
 
 } // namespace internal
index 2a6e5f2ba5e0bcacb7cb6e16cddd5adf4031821d..4fdf0efd342f9f882d380774272ac26307447e83 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -47,6 +47,7 @@
 
 #include "gromacs/options/abstractoption.h"
 #include "gromacs/options/abstractoptionstorage.h"
+#include "gromacs/options/optionsection.h"
 #include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
@@ -73,6 +74,22 @@ IOptionsContainer::~IOptionsContainer()
 {
 }
 
+/********************************************************************
+ * IOptionsContainerWithSections
+ */
+
+IOptionsContainerWithSections::~IOptionsContainerWithSections()
+{
+}
+
+/********************************************************************
+ * IOptionSectionStorage
+ */
+
+IOptionSectionStorage::~IOptionSectionStorage()
+{
+}
+
 /********************************************************************
  * OptionsImpl
  */
@@ -80,76 +97,125 @@ IOptionsContainer::~IOptionsContainer()
 namespace internal
 {
 
-OptionsImpl::OptionsImpl(const char *name, const char * /*title*/)
-    : name_(name != NULL ? name : ""), rootGroup_(this),
-      parent_(NULL)
+OptionsImpl::OptionsImpl()
+    : rootSection_(managers_, nullptr, "")
+{
+}
+
+/********************************************************************
+ * OptionSectionImpl
+ */
+
+OptionSectionImpl *
+OptionSectionImpl::addSectionImpl(const AbstractOptionSection &section)
+{
+    const char *name = section.name_;
+    // Make sure that there are no duplicate sections.
+    GMX_RELEASE_ASSERT(findSection(name) == NULL, "Duplicate subsection name");
+    std::unique_ptr<IOptionSectionStorage> storage(section.createStorage());
+    subsections_.push_back(SectionPointer(new OptionSectionImpl(managers_, std::move(storage), name)));
+    return subsections_.back().get();
+}
+
+IOptionsContainer &OptionSectionImpl::addGroup()
 {
+    return rootGroup_.addGroup();
 }
 
-Options *OptionsImpl::findSubSection(const char *name) const
+OptionInfo *OptionSectionImpl::addOptionImpl(const AbstractOption &settings)
 {
-    SubSectionList::const_iterator i;
-    for (i = subSections_.begin(); i != subSections_.end(); ++i)
+    return rootGroup_.addOptionImpl(settings);
+}
+
+OptionSectionImpl *OptionSectionImpl::findSection(const char *name) const
+{
+    for (const auto &section : subsections_)
     {
-        if ((*i)->name() == name)
+        if (section->name_ == name)
         {
-            return *i;
+            return section.get();
         }
     }
-    return NULL;
+    return nullptr;
 }
 
-AbstractOptionStorage *OptionsImpl::findOption(const char *name) const
+AbstractOptionStorage *OptionSectionImpl::findOption(const char *name) const
 {
     OptionMap::const_iterator i = optionMap_.find(name);
     if (i == optionMap_.end())
     {
-        return NULL;
+        return nullptr;
     }
     return i->second.get();
 }
 
-void OptionsImpl::startSource()
+void OptionSectionImpl::start()
 {
-    OptionMap::const_iterator i;
-    for (i = optionMap_.begin(); i != optionMap_.end(); ++i)
+    for (const auto &entry : optionMap_)
+    {
+        entry.second->startSource();
+    }
+    if (storage_ != nullptr)
+    {
+        if (!storageInitialized_)
+        {
+            storage_->initStorage();
+            storageInitialized_ = true;
+        }
+        storage_->startSection();
+    }
+}
+
+void OptionSectionImpl::finish()
+{
+    // TODO: Consider how to customize these error messages based on context.
+    ExceptionInitializer  errors("Invalid input values");
+    for (const auto &entry : optionMap_)
+    {
+        AbstractOptionStorage &option = *entry.second;
+        try
+        {
+            option.finish();
+        }
+        catch (UserInputError &ex)
+        {
+            ex.prependContext("In option " + option.name());
+            errors.addCurrentExceptionAsNested();
+        }
+    }
+    if (errors.hasNestedExceptions())
     {
-        AbstractOptionStorage &option = *i->second;
-        option.startSource();
+        // TODO: This exception type may not always be appropriate.
+        GMX_THROW(InvalidInputError(errors));
     }
-    SubSectionList::const_iterator j;
-    for (j = subSections_.begin(); j != subSections_.end(); ++j)
+    if (storage_ != nullptr)
     {
-        Options &section = **j;
-        section.impl_->startSource();
+        storage_->finishSection();
     }
 }
 
 /********************************************************************
- * OptionsImpl::Group
+ * OptionSectionImpl::Group
  */
 
-IOptionsContainer &OptionsImpl::Group::addGroup()
+IOptionsContainer &OptionSectionImpl::Group::addGroup()
 {
-    subgroups_.push_back(Group(parent_));
+    subgroups_.emplace_back(parent_);
     return subgroups_.back();
 }
 
-OptionInfo *OptionsImpl::Group::addOption(const AbstractOption &settings)
+OptionInfo *OptionSectionImpl::Group::addOptionImpl(const AbstractOption &settings)
 {
-    OptionsImpl *root = parent_;
-    while (root->parent_ != NULL)
-    {
-        root = root->parent_->impl_.get();
-    }
-    AbstractOptionStoragePointer         option(settings.createStorage(root->managers_));
+    OptionSectionImpl::AbstractOptionStoragePointer
+         option(settings.createStorage(parent_->managers_));
     options_.reserve(options_.size() + 1);
-    std::pair<OptionMap::iterator, bool> insertionResult =
+    auto insertionResult =
         parent_->optionMap_.insert(std::make_pair(option->name(),
                                                   std::move(option)));
     if (!insertionResult.second)
     {
-        GMX_THROW(APIError("Duplicate option: " + option->name()));
+        const std::string &name = insertionResult.first->second->name();
+        GMX_THROW(APIError("Duplicate option: " + name));
     }
     AbstractOptionStorage &insertedOption = *insertionResult.first->second;
     options_.push_back(&insertedOption);
@@ -164,8 +230,8 @@ using internal::OptionsImpl;
  * Options
  */
 
-Options::Options(const char *name, const char *title)
-    : impl_(new OptionsImpl(name, title))
+Options::Options()
+    : impl_(new OptionsImpl)
 {
 }
 
@@ -173,90 +239,47 @@ Options::~Options()
 {
 }
 
-const std::string &Options::name() const
-{
-    return impl_->name_;
-}
-
 
 void Options::addManager(IOptionManager *manager)
 {
-    GMX_RELEASE_ASSERT(impl_->parent_ == NULL,
-                       "Can only add a manager in a top-level Options object");
     // This ensures that all options see the same set of managers.
-    GMX_RELEASE_ASSERT(impl_->optionMap_.empty(),
+    GMX_RELEASE_ASSERT(impl_->rootSection_.optionMap_.empty(),
                        "Can only add a manager before options");
     // This check could be relaxed if we instead checked that the subsections
     // do not have options.
-    GMX_RELEASE_ASSERT(impl_->subSections_.empty(),
+    GMX_RELEASE_ASSERT(impl_->rootSection_.subsections_.empty(),
                        "Can only add a manager before subsections");
     impl_->managers_.add(manager);
 }
 
-void Options::addSubSection(Options *section)
+internal::OptionSectionImpl *Options::addSectionImpl(const AbstractOptionSection &section)
 {
-    // This is required, because managers are used from the root Options
-    // object, so they are only seen after the subsection has been added.
-    GMX_RELEASE_ASSERT(section->impl_->optionMap_.empty(),
-                       "Can only add a subsection before it has any options");
-    GMX_RELEASE_ASSERT(section->impl_->managers_.empty(),
-                       "Can only have managers in a top-level Options object");
-    // Make sure that section is not already inserted somewhere.
-    GMX_RELEASE_ASSERT(section->impl_->parent_ == NULL,
-                       "Cannot add as subsection twice");
-    // Make sure that there are no duplicate sections.
-    GMX_RELEASE_ASSERT(impl_->findSubSection(section->name().c_str()) == NULL,
-                       "Duplicate subsection name");
-    impl_->subSections_.push_back(section);
-    section->impl_->parent_ = this;
+    return impl_->rootSection_.addSectionImpl(section);
 }
 
 IOptionsContainer &Options::addGroup()
 {
-    return impl_->rootGroup_.addGroup();
+    return impl_->rootSection_.addGroup();
+}
+
+OptionInfo *Options::addOptionImpl(const AbstractOption &settings)
+{
+    return impl_->rootSection_.addOptionImpl(settings);
 }
 
-OptionInfo *Options::addOption(const AbstractOption &settings)
+OptionSectionInfo &Options::rootSection()
 {
-    return impl_->rootGroup_.addOption(settings);
+    return impl_->rootSection_.info();
+}
+
+const OptionSectionInfo &Options::rootSection() const
+{
+    return impl_->rootSection_.info();
 }
 
 void Options::finish()
 {
-    // TODO: Consider how to customize these error messages based on context.
-    ExceptionInitializer                    errors("Invalid input values");
-    OptionsImpl::OptionMap::const_iterator  i;
-    for (i = impl_->optionMap_.begin(); i != impl_->optionMap_.end(); ++i)
-    {
-        AbstractOptionStorage &option = *i->second;
-        try
-        {
-            option.finish();
-        }
-        catch (UserInputError &ex)
-        {
-            ex.prependContext("In option " + option.name());
-            errors.addCurrentExceptionAsNested();
-        }
-    }
-    OptionsImpl::SubSectionList::const_iterator j;
-    for (j = impl_->subSections_.begin(); j != impl_->subSections_.end(); ++j)
-    {
-        Options &section = **j;
-        try
-        {
-            section.finish();
-        }
-        catch (const UserInputError &)
-        {
-            errors.addCurrentExceptionAsNested();
-        }
-    }
-    if (errors.hasNestedExceptions())
-    {
-        // TODO: This exception type may not always be appropriate.
-        GMX_THROW(InvalidInputError(errors));
-    }
+    impl_->rootSection_.finish();
 }
 
 } // namespace gmx
index 944606db1ba7ab1bfd451b0b1d5c511ed5b8c307..a4ba843633ac1889012a00e235958f30b8167844 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 
 #include <string>
 
-#include "gromacs/options/ioptionscontainer.h"
+#include "gromacs/options/ioptionscontainerwithsections.h"
 #include "gromacs/utility/classhelpers.h"
 
 namespace gmx
 {
 
 class AbstractOption;
+class OptionSection;
+class OptionSectionInfo;
 class OptionsAssigner;
-class OptionsIterator;
 
 namespace internal
 {
@@ -88,7 +89,7 @@ class IOptionManager
  * Collection of options.
  *
  * See \ref module_options for an overview of how the options work.
- * The IOptionsContainer interface documents how to add options.
+ * The IOptionsContainerWithSections interface documents how to add options.
  *
  * In order to keep the public interface of this class simple, functionality
  * to assign values to options is provided by a separate OptionsAssigner class.
@@ -98,23 +99,13 @@ class IOptionManager
  * \inpublicapi
  * \ingroup module_options
  */
-class Options : public IOptionsContainer
+class Options : public IOptionsContainerWithSections
 {
     public:
-        /*! \brief
-         * Initializes the name and title of an option collection.
-         *
-         * \param[in] name  Single-word name.
-         * \param[in] title Descriptive title.
-         *
-         * Copies the input strings.
-         */
-        Options(const char *name, const char *title);
+        //! Initializes an empty options root container.
+        Options();
         ~Options();
 
-        //! Returns the short name of the option collection.
-        const std::string &name() const;
-
         /*! \brief
          * Adds an option manager.
          *
@@ -133,35 +124,17 @@ class Options : public IOptionsContainer
          * The Options object (and its contained options) only stores a
          * reference to the object.
          *
-         * This method cannot be called after adding options or subsections.
+         * This method cannot be called after adding options or sections.
          */
         void addManager(IOptionManager *manager);
 
-        /*! \brief
-         * Adds an option collection as a subsection of this collection.
-         *
-         * \param[in] section Subsection to add.
-         *
-         * The name() field of \p section is used as the name of the
-         * subsection.  If an attempt is made to add two different subsections
-         * with the same name, this function asserts.
-         *
-         * \p section should not have any options added at the point this
-         * method is called.
-         *
-         * Only a pointer to the provided object is stored.  The caller is
-         * responsible that the object exists for the lifetime of the
-         * collection.
-         * It is not possible to add the same Options object as a subsection to
-         * several different Options.
-         * If an attempt is made, the function asserts.
-         */
-        void addSubSection(Options *section);
-
         // From IOptionsContainer
         virtual IOptionsContainer &addGroup();
-        virtual OptionInfo *addOption(const AbstractOption &settings);
-        using IOptionsContainer::addOption;
+
+        //! Returns a handle to the root section.
+        OptionSectionInfo       &rootSection();
+        //! Returns a handle to the root section.
+        const OptionSectionInfo &rootSection() const;
 
         /*! \brief
          * Notifies the collection that all option values are assigned.
@@ -180,16 +153,16 @@ class Options : public IOptionsContainer
         void finish();
 
     private:
+        // From IOptionsContainerWithSections
+        virtual internal::OptionSectionImpl *
+        addSectionImpl(const AbstractOptionSection &section);
+        // From IOptionsContainer
+        virtual OptionInfo *addOptionImpl(const AbstractOption &settings);
+
         PrivateImplPointer<internal::OptionsImpl> impl_;
 
-        //! Needed for the implementation to access subsections.
-        friend class internal::OptionsImpl;
         //! Needed to be able to extend the interface of this object.
         friend class OptionsAssigner;
-        //! Needed to be able to extend the interface of this object.
-        friend class OptionsIterator;
-        //! Needed to be able to extend the interface of this object.
-        friend class OptionsModifyingIterator;
 };
 
 } // namespace gmx
index 2842655c54f438b38559d32d2989383ec69d1b39..7763f25961431f0c486fde8a6f7319a30e4e6c0d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -49,6 +49,7 @@
 #include "gromacs/options/options.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/variant.h"
 
 #include "options-impl.h"
 
@@ -67,13 +68,16 @@ namespace gmx
 class OptionsAssigner::Impl
 {
     public:
+        //! Shorthand for the internal type used to represent a section.
+        typedef internal::OptionSectionImpl Section;
+
         //! Sets the option object to assign to.
         explicit Impl(Options *options);
 
         //! Returns true if a subsection has been set.
-        bool inSubSection() const { return sectionStack_.size() > 1; }
+        bool inSection() const { return sectionStack_.size() > 1; }
         //! Returns the Options object for the current section.
-        Options &currentSection() const { return *sectionStack_.back(); }
+        Section &currentSection() const { return *sectionStack_.back(); }
         /*! \brief
          * Finds an option by the given name.
          *
@@ -95,7 +99,7 @@ class OptionsAssigner::Impl
          *
          * The first element always points to \a options_.
          */
-        std::vector<Options *>  sectionStack_;
+        std::vector<Section *>  sectionStack_;
         //! Current option being assigned to, or NULL if none.
         AbstractOptionStorage  *currentOption_;
         /*! \brief
@@ -113,7 +117,7 @@ OptionsAssigner::Impl::Impl(Options *options)
     : options_(*options), bAcceptBooleanNoPrefix_(false),
       currentOption_(NULL), currentValueCount_(0), reverseBoolean_(false)
 {
-    sectionStack_.push_back(&options_);
+    sectionStack_.push_back(&options_.impl_->rootSection_);
 }
 
 AbstractOptionStorage *
@@ -121,13 +125,13 @@ OptionsAssigner::Impl::findOption(const char *name)
 {
     GMX_RELEASE_ASSERT(currentOption_ == NULL,
                        "Cannot search for another option while processing one");
-    const Options         &section = currentSection();
-    AbstractOptionStorage *option  = section.impl_->findOption(name);
+    const Section         &section = currentSection();
+    AbstractOptionStorage *option  = section.findOption(name);
     if (option == NULL && bAcceptBooleanNoPrefix_)
     {
         if (name[0] == 'n' && name[1] == 'o')
         {
-            option = section.impl_->findOption(name + 2);
+            option = section.findOption(name + 2);
             if (option != NULL && option->isBoolean())
             {
                 reverseBoolean_ = true;
@@ -161,17 +165,18 @@ void OptionsAssigner::setAcceptBooleanNoPrefix(bool bEnabled)
 
 void OptionsAssigner::start()
 {
-    impl_->options_.impl_->startSource();
+    impl_->options_.impl_->rootSection_.start();
 }
 
-void OptionsAssigner::startSubSection(const char *name)
+void OptionsAssigner::startSection(const char *name)
 {
-    Options *section = impl_->currentSection().impl_->findSubSection(name);
+    Impl::Section *section = impl_->currentSection().findSection(name);
     if (section == NULL)
     {
         GMX_THROW(InvalidInputError("Unknown subsection"));
     }
     impl_->sectionStack_.push_back(section);
+    section->start();
 }
 
 void OptionsAssigner::startOption(const char *name)
@@ -197,6 +202,11 @@ bool OptionsAssigner::tryStartOption(const char *name)
 }
 
 void OptionsAssigner::appendValue(const std::string &value)
+{
+    appendValue(Variant(value));
+}
+
+void OptionsAssigner::appendValue(const Variant &value)
 {
     AbstractOptionStorage *option = impl_->currentOption_;
     GMX_RELEASE_ASSERT(option != NULL, "startOption() not called");
@@ -214,8 +224,7 @@ void OptionsAssigner::finishOption()
         if (impl_->currentValueCount_ == 0)
         {
             // Should not throw, otherwise something is wrong.
-            // TODO: Get rid of the hard-coded values.
-            option->appendValue(impl_->reverseBoolean_ ? "0" : "1");
+            option->appendValue(Variant::create<bool>(!impl_->reverseBoolean_));
         }
         else if (impl_->reverseBoolean_)
         {
@@ -231,17 +240,19 @@ void OptionsAssigner::finishOption()
     }
 }
 
-void OptionsAssigner::finishSubSection()
+void OptionsAssigner::finishSection()
 {
     // Should only be called if we are in a subsection.
-    GMX_RELEASE_ASSERT(impl_->inSubSection(), "startSubSection() not called");
+    GMX_RELEASE_ASSERT(impl_->inSection(), "startSection() not called");
+    Impl::Section *section = impl_->sectionStack_.back();
+    section->finish();
     impl_->sectionStack_.pop_back();
 }
 
 void OptionsAssigner::finish()
 {
     GMX_RELEASE_ASSERT(impl_->currentOption_ == NULL, "finishOption() not called");
-    GMX_RELEASE_ASSERT(!impl_->inSubSection(), "finishSubSection() not called");
+    GMX_RELEASE_ASSERT(!impl_->inSection(), "finishSection() not called");
 }
 
 } // namespace gmx
index 35bb70dce9225e3e5b71146ef832a3df43086011..cdefa7258276df7cb263d018d996e6535bbfbaad 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -53,6 +53,7 @@ namespace gmx
 {
 
 class Options;
+class Variant;
 
 /*! \libinternal \brief
  * Decorator class for assigning values to Options.
@@ -70,11 +71,11 @@ class Options;
    assigner.startOption("opt1");
    assigner.appendValue("3");
    assigner.finishOption();
-   assigner.startSubSection("section");
+   assigner.startSection("section");
    assigner.startOption("opt2"); // Now in the subsection
    assigner.appendValue("yes");
    assigner.finishOption();
-   assigner.finishSubSection()
+   assigner.finishSection()
    assigner.startOption("opt3"); // Again in the main options
    assigner.appendValue("2");
    assigner.finishOption();
@@ -124,7 +125,7 @@ class OptionsAssigner
          *
          * Strong exception safety guarantee.
          */
-        void startSubSection(const char *name);
+        void startSection(const char *name);
         /*! \brief
          * Starts assigning values for an option.
          *
@@ -145,7 +146,7 @@ class OptionsAssigner
         /*! \brief
          * Appends a value to the value list of the current option.
          *
-         * \param[in] value  String representation of the value to assign.
+         * \param[in] value  Value to assign.
          * \throws InvalidInputError if the value cannot be converted or if
          *      there are too many values for an option.
          *
@@ -166,6 +167,14 @@ class OptionsAssigner
          * OptionStorageTemplate::convertValue() method of the storage class
          * implementing the option where the value is assigned to.
          */
+        void appendValue(const Variant &value);
+        /*! \brief
+         * Appends a value to the value list of the current option.
+         *
+         * \param[in] value  Value to assign.
+         *
+         * See appendValue(const Variant &) for more details.
+         */
         void appendValue(const std::string &value);
         /*! \brief
          * Finish assigning values for the current option.
@@ -186,7 +195,7 @@ class OptionsAssigner
          *
          * Does not throw.
          */
-        void finishSubSection();
+        void finishSection();
         /*! \brief
          * Finish assigning options through the object.
          *
diff --git a/src/gromacs/options/optionsection.cpp b/src/gromacs/options/optionsection.cpp
new file mode 100644 (file)
index 0000000..5578d36
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+#include "gmxpre.h"
+
+#include "optionsection.h"
+
+#include "gromacs/options/isectionstorage.h"
+
+namespace gmx
+{
+
+namespace
+{
+
+class OptionSectionStorage : public IOptionSectionStorage
+{
+    public:
+        virtual void initStorage() {}
+        virtual void startSection() {}
+        virtual void finishSection() {}
+};
+
+}   // namespace
+
+IOptionSectionStorage *OptionSection::createStorage() const
+{
+    return new OptionSectionStorage();
+}
+
+} // namespace gmx
diff --git a/src/gromacs/options/optionsection.h b/src/gromacs/options/optionsection.h
new file mode 100644 (file)
index 0000000..b5f5479
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \file
+ * \brief
+ * Declares gmx::OptionSection and gmx::OptionSectionInfo.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inpublicapi
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_OPTIONSECTION_H
+#define GMX_OPTIONS_OPTIONSECTION_H
+
+#include "gromacs/options/abstractsection.h"
+#include "gromacs/utility/classhelpers.h"
+
+namespace gmx
+{
+
+class OptionSectionHandle;
+
+/*! \brief
+ * Declares a simple option section.
+ *
+ * This class declares a simple section that only provides structure for
+ * grouping the options, but does not otherwise influence the behavior of the
+ * contained options.
+ *
+ * \inpublicapi
+ * \ingroup module_options
+ */
+class OptionSection : public AbstractOptionSection
+{
+    public:
+        //! AbstractOptionSectionHandle corresponding to this option type.
+        typedef OptionSectionHandle HandleType;
+
+        //! Creates a section with the given name.
+        explicit OptionSection(const char *name) : AbstractOptionSection(name) {}
+
+    private:
+        virtual IOptionSectionStorage *createStorage() const;
+};
+
+/*! \brief
+ * Allows adding options to an OptionSection.
+ *
+ * An instance of this class is returned from
+ * IOptionsContainerWithSections::addSection(), and supports adding options and
+ * subsections to a section created with OptionSection.
+ *
+ * \inpublicapi
+ * \ingroup module_options
+ */
+class OptionSectionHandle : public AbstractOptionSectionHandle
+{
+    public:
+        //! Wraps a given section storage object.
+        explicit OptionSectionHandle(internal::OptionSectionImpl *section)
+            : AbstractOptionSectionHandle(section)
+        {
+        }
+};
+
+class OptionSectionInfo : public AbstractOptionSectionInfo
+{
+    public:
+        //! Wraps a given section storage object.
+        explicit OptionSectionInfo(internal::OptionSectionImpl *section)
+            : AbstractOptionSectionInfo(section)
+        {
+        }
+};
+
+} // namespace gmx
+
+#endif
index 108841e9cfa9d81904331d6c51d68ae190b2a5b1..6ccc2915150da27b609d89ccfa1317bf9438f74a 100644 (file)
 
 #include "gromacs/options/abstractoption.h"
 #include "gromacs/options/abstractoptionstorage.h"
+#include "gromacs/options/valuestore.h"
+#include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/variant.h"
+
+#include "valueconverter.h"
 
 namespace gmx
 {
@@ -63,15 +68,13 @@ class Options;
  *
  * \tparam T Assignable type that stores a single option value.
  *
- * Provides an implementation of the clearSet(), valueCount(), and processSet()
- * methods of AbstractOptionStorage, as well as a basic no-action
- * implementation of processAll().  Two new virtual methods are added:
- * processSetValues() and refreshValues().  The default implementation of
- * processSetValues() does nothing, and refreshValues() is used to update
- * secondary storage after values have been added/changed.
- * This leaves typeString(), formatValue(), and convertValue() to be
- * implemented in derived classes.  processSetValues() and processAll() can
- * also be implemented if necessary.
+ * Provides an implementation of the clearSet(), valueCount(), processSet(),
+ * and defaultValuesAsStrings() methods of AbstractOptionStorage, as well as a
+ * basic no-action implementation of processAll().  Two new virtual methods are
+ * added: processSetValues() and formatSingleValue().
+ * This leaves typeString(), convertValue() and formatStringValue() to be
+ * implemented in derived classes.
+ * processSetValues() and processAll() can also be implemented if necessary.
  *
  * Implements transaction support for adding values within a set: all calls to
  * addValue() add the value to a temporary storage, processSetValues() operates
@@ -91,25 +94,28 @@ class OptionStorageTemplate : public AbstractOptionStorage
         //! Type of the container that contains the current values.
         typedef std::vector<T> ValueList;
 
-        virtual ~OptionStorageTemplate();
-
         // No implementation in this class for the pure virtual methods, but
         // the declarations are still included for clarity.
         // The various copydoc calls are needed with Doxygen 1.8.10, although
         // things work without with 1.8.5...
         virtual std::string typeString() const = 0;
         //! \copydoc gmx::AbstractOptionStorage::valueCount()
-        virtual int valueCount() const { return static_cast<int>(values_->size()); }
-        /*! \copydoc gmx::AbstractOptionStorage::formatValue()
+        virtual int valueCount() const { return store_->valueCount(); }
+        //! \copydoc gmx::AbstractOptionStorage::defaultValues()
+        virtual std::vector<Variant> defaultValues() const;
+        /*! \copydoc gmx::AbstractOptionStorage::defaultValuesAsStrings()
          *
-         * OptionStorageTemplate implements handling of DefaultValueIfSetIndex
-         * in this method, as well as checking that \p i is a valid index.
+         * OptionStorageTemplate implements handling of defaultValueIfSet()
+         * cases and composing the vector.
          * Derived classes must implement formatSingleValue() to provide the
          * actual formatting for a value of type \p T.
          */
-        virtual std::string formatValue(int i) const;
+        virtual std::vector<std::string> defaultValuesAsStrings() const;
 
     protected:
+        //! Smart pointer for managing the final storage interface.
+        typedef std::unique_ptr<IOptionValueStore<T> > StorePointer;
+
         /*! \brief
          * Initializes the storage from option settings.
          *
@@ -125,12 +131,14 @@ class OptionStorageTemplate : public AbstractOptionStorage
          * Initializes the storage from base option settings.
          *
          * \param[in] settings  Option settings.
+         * \param[in] store     Final storage location.
          * \throws  APIError if invalid settings have been provided.
          *
          * This constructor works for cases where there is no matching
          * OptionTemplate (e.g., EnumOption).
          */
-        explicit OptionStorageTemplate(const AbstractOption &settings);
+        OptionStorageTemplate(const AbstractOption &settings,
+                              StorePointer          store);
 
         //! \copydoc gmx::AbstractOptionStorage::clearSet()
         virtual void clearSet();
@@ -143,7 +151,7 @@ class OptionStorageTemplate : public AbstractOptionStorage
          * should be considered whether the implementation can be made strongly
          * exception safe.
          */
-        virtual void convertValue(const std::string &value) = 0;
+        virtual void convertValue(const Variant &value) = 0;
         /*! \brief
          * Processes values for a set after all have been converted.
          *
@@ -184,16 +192,11 @@ class OptionStorageTemplate : public AbstractOptionStorage
          * \returns   \p value formatted as a string.
          *
          * The derived class must provide this method to format values a
-         * strings.  Called by formatValue() to do the actual formatting.
+         * strings.  Called by defaultValuesAsStrings() to do the actual
+         * formatting.
          */
         virtual std::string formatSingleValue(const T &value) const = 0;
 
-        /*! \brief
-         * Removes all values from the storage.
-         *
-         * Does not throw.
-         */
-        void clear() { values_->clear(); }
         /*! \brief
          * Adds a value to a temporary storage.
          *
@@ -226,24 +229,9 @@ class OptionStorageTemplate : public AbstractOptionStorage
          * See addValue() for cases where this method should be used in derived
          * classes.
          *
-         * Calls refreshValues() and clearSet() if it is successful.
+         * Calls clearSet() if it is successful.
          */
         void commitValues();
-        /*! \brief
-         * Updates alternative store locations.
-         *
-         * Derived classes should override this method if they implement
-         * alternative store locations, and copy/translate values from the
-         * values() vector to these alternative storages.  They should also
-         * call the base class implementation as part of their implementation.
-         *
-         * Should be called in derived classes if values are modified directly
-         * through the values() method, e.g., in processAll().  Does not need
-         * to be called if commitValues() is used.
-         *
-         * Does not throw, and derived classes should not change that.
-         */
-        virtual void refreshValues();
 
         /*! \brief
          * Sets the default value for the option.
@@ -270,71 +258,148 @@ class OptionStorageTemplate : public AbstractOptionStorage
          * Provides derived classes access to the current list of values.
          *
          * The non-const variant should only be used from processAll() in
-         * derived classes if necessary, and refreshValues() should be called
-         * if any changes are made.
+         * derived classes if necessary.
          */
-        ValueList       &values() { return *values_; }
+        ArrayRef<T>      values() { return store_->values(); }
         //! Provides derived classes access to the current list of values.
-        const ValueList &values() const { return *values_; }
+        ConstArrayRef<T> values() const { return store_->values(); }
 
     private:
+        //! Creates the internal storage object for final values..
+        StorePointer createStore(ValueList *storeVector,
+                                 T *store, int *storeCount,
+                                 int initialCount);
+
         /*! \brief
          * Vector for temporary storage of values before commitSet() is called.
          */
         ValueList               setValues_;
+        //! Final storage for option values.
+        const StorePointer      store_;
+        // This never releases ownership.
+        std::unique_ptr<T>      defaultValueIfSet_;
+
+        // Copy and assign disallowed by base.
+};
+
+
+/*! \libinternal \brief
+ * Simplified option storage template for options that have one-to-one value
+ * conversion.
+ *
+ * \tparam T Assignable type that stores a single option value.
+ *
+ * To implement an option that always map a single input value to a single
+ * output value, derive from this class instead of OptionStorageTemplate.
+ * This class implements convertValue() in terms of two new virtual methods:
+ * initConverter() and processValue().
+ *
+ * To specify how different types of values need to be converted, implement
+ * initConverter().
+ * To do common post-processing of the values after conversion, but before they
+ * are added to the underlying storage, override processValue().
+ *
+ * \inlibraryapi
+ * \ingroup module_options
+ */
+template <typename T>
+class OptionStorageTemplateSimple : public OptionStorageTemplate<T>
+{
+    public:
+        //! Alias for the template class for use in base classes.
+        typedef OptionStorageTemplateSimple<T> MyBase;
+
+    protected:
+        //! Alias for the converter parameter type for initConverter().
+        typedef OptionValueConverterSimple<T> ConverterType;
+
+        //! Initializes the storage.
+        template <class U>
+        explicit OptionStorageTemplateSimple(const OptionTemplate<T, U> &settings,
+                                             OptionFlags staticFlags = OptionFlags())
+            : OptionStorageTemplate<T>(settings, staticFlags), initialized_(false)
+        {
+        }
+        //! Initializes the storage.
+        OptionStorageTemplateSimple(const AbstractOption                            &settings,
+                                    typename OptionStorageTemplate<T>::StorePointer  store)
+            : OptionStorageTemplate<T>(settings, std::move(store)), initialized_(false)
+        {
+        }
+
+        virtual std::vector<Variant>
+        normalizeValues(const std::vector<Variant> &values) const
+        {
+            const_cast<MyBase *>(this)->ensureConverterInitialized();
+            std::vector<Variant> result;
+            for (const auto &value : values)
+            {
+                result.push_back(
+                        Variant::create<T>(
+                                processValue(converter_.convert(value))));
+            }
+            return result;
+        }
+
         /*! \brief
-         * Vector for primary storage of option values.
+         * Specifies how different types are converted.
          *
-         * Is never NULL; points either to externally provided vector, or an
-         * internally allocated one.  The allocation is performed by the
-         * constructor.
+         * See OptionValueConverterSimple for more details.
+         */
+        virtual void initConverter(ConverterType *converter) = 0;
+        /*! \brief
+         * Post-processes a value after conversion to the output type.
+         *
+         * \param[in] value  Value after conversion.
+         * \returns   Value to store for the option.
          *
-         * Primarily, modifications to values are done only to this storage,
-         * and other storage locations are updated only when refreshValues() is
-         * called.
+         * The default implementation only provides an identity mapping.
          */
-        ValueList                   *values_;
-        T                           *store_;
-        int                         *countptr_;
-        // These never release ownership.
-        std::unique_ptr<ValueList>   ownedValues_;
-        std::unique_ptr<T>           defaultValueIfSet_;
+        virtual T processValue(const T &value) const
+        {
+            return value;
+        }
 
-        // Copy and assign disallowed by base.
+    private:
+        virtual void convertValue(const Variant &variant)
+        {
+            ensureConverterInitialized();
+            this->addValue(processValue(converter_.convert(variant)));
+        }
+        void ensureConverterInitialized()
+        {
+            if (!initialized_)
+            {
+                initConverter(&converter_);
+                initialized_ = true;
+            }
+        }
+
+        ConverterType  converter_;
+        bool           initialized_;
 };
 
 
+/********************************************************************
+ * OptionStorageTemplate implementation
+ */
+
 template <typename T>
 template <class U>
 OptionStorageTemplate<T>::OptionStorageTemplate(const OptionTemplate<T, U> &settings,
                                                 OptionFlags staticFlags)
     : AbstractOptionStorage(settings, staticFlags),
-      values_(settings.storeVector_),
-      store_(settings.store_),
-      countptr_(settings.countptr_)
+      store_(createStore(settings.storeVector_,
+                         settings.store_, settings.countptr_,
+                         (settings.isVector() ?
+                          settings.maxValueCount_ : settings.minValueCount_)))
 {
-    // If the maximum number of values is not known, storage to
-    // caller-allocated memory is unsafe.
-    if (store_ != NULL && (maxValueCount() < 0 || hasFlag(efOption_MultipleTimes)))
-    {
-        GMX_THROW(APIError("Cannot set user-allocated storage for arbitrary number of values"));
-    }
-    if (values_ == NULL)
-    {
-        ownedValues_.reset(new std::vector<T>);
-        values_ = ownedValues_.get();
-    }
     if (hasFlag(efOption_NoDefaultValue)
         && (settings.defaultValue_ != NULL
             || settings.defaultValueIfSet_ != NULL))
     {
         GMX_THROW(APIError("Option does not support default value, but one is set"));
     }
-    if (store_ != NULL && countptr_ == NULL && !isVector()
-        && minValueCount() != maxValueCount())
-    {
-        GMX_THROW(APIError("Count storage is not set, although the number of produced values is not known"));
-    }
     if (!hasFlag(efOption_NoDefaultValue))
     {
         setFlag(efOption_HasDefaultValue);
@@ -342,16 +407,6 @@ OptionStorageTemplate<T>::OptionStorageTemplate(const OptionTemplate<T, U> &sett
         {
             setDefaultValue(*settings.defaultValue_);
         }
-        else if (ownedValues_.get() != NULL && store_ != NULL)
-        {
-            values_->clear();
-            int count = (settings.isVector() ?
-                         settings.maxValueCount_ : settings.minValueCount_);
-            for (int i = 0; i < count; ++i)
-            {
-                values_->push_back(store_[i]);
-            }
-        }
         if (settings.defaultValueIfSet_ != NULL)
         {
             setDefaultValueIfSet(*settings.defaultValueIfSet_);
@@ -361,36 +416,88 @@ OptionStorageTemplate<T>::OptionStorageTemplate(const OptionTemplate<T, U> &sett
 
 
 template <typename T>
-// cppcheck-suppress uninitMemberVar
-OptionStorageTemplate<T>::OptionStorageTemplate(const AbstractOption &settings)
-    : AbstractOptionStorage(settings, OptionFlags()),
-      store_(NULL), countptr_(NULL),
-      ownedValues_(new std::vector<T>())
+OptionStorageTemplate<T>::OptionStorageTemplate(const AbstractOption &settings,
+                                                StorePointer          store)
+    : AbstractOptionStorage(settings, OptionFlags()), store_(std::move(store))
 {
-    values_ = ownedValues_.get();
 }
 
 
 template <typename T>
-OptionStorageTemplate<T>::~OptionStorageTemplate()
+std::unique_ptr<IOptionValueStore<T> > OptionStorageTemplate<T>::createStore(
+        ValueList *storeVector, T *store, int *storeCount, int initialCount)
 {
+    if (storeVector != nullptr)
+    {
+        GMX_RELEASE_ASSERT(store == nullptr && storeCount == nullptr,
+                           "Cannot specify more than one storage location");
+        return StorePointer(new OptionValueStoreVector<T>(storeVector));
+    }
+    else if (store != nullptr)
+    {
+        // If the maximum number of values is not known, storage to
+        // caller-allocated memory is unsafe.
+        if (maxValueCount() < 0 || hasFlag(efOption_MultipleTimes))
+        {
+            GMX_THROW(APIError("Cannot set user-allocated storage for arbitrary number of values"));
+        }
+        if (storeCount == nullptr && !isVector() && minValueCount() != maxValueCount())
+        {
+            GMX_THROW(APIError("Count storage is not set, although the number of produced values is not known"));
+        }
+        if (hasFlag(efOption_NoDefaultValue))
+        {
+            initialCount = 0;
+        }
+        return StorePointer(new OptionValueStorePlain<T>(store, storeCount, initialCount));
+    }
+    GMX_RELEASE_ASSERT(storeCount == nullptr,
+                       "Cannot specify count storage without value storage");
+    return StorePointer(new OptionValueStoreNull<T>());
 }
 
 
 template <typename T>
-std::string OptionStorageTemplate<T>::formatValue(int i) const
+std::vector<Variant> OptionStorageTemplate<T>::defaultValues() const
 {
-    GMX_RELEASE_ASSERT(i == DefaultValueIfSetIndex || (i >= 0 && i < valueCount()),
-                       "Invalid value index");
-    if (i == DefaultValueIfSetIndex)
+    std::vector<Variant> result;
+    if (hasFlag(efOption_NoDefaultValue))
     {
+        return result;
+    }
+    GMX_RELEASE_ASSERT(hasFlag(efOption_HasDefaultValue),
+                       "Current option implementation can only provide default values before assignment");
+    for (const auto &value : values())
+    {
+        result.push_back(Variant::create<T>(value));
+    }
+    return result;
+}
+
+
+template <typename T>
+std::vector<std::string> OptionStorageTemplate<T>::defaultValuesAsStrings() const
+{
+    std::vector<std::string> result;
+    if (hasFlag(efOption_NoDefaultValue))
+    {
+        return result;
+    }
+    GMX_RELEASE_ASSERT(hasFlag(efOption_HasDefaultValue),
+                       "Current option implementation can only provide default values before assignment");
+    for (const auto &value : values())
+    {
+        result.push_back(formatSingleValue(value));
+    }
+    if (result.empty() || (result.size() == 1 && result[0].empty()))
+    {
+        result.clear();
         if (defaultValueIfSet_.get() != NULL)
         {
-            return formatSingleValue(*defaultValueIfSet_);
+            result.push_back(formatSingleValue(*defaultValueIfSet_));
         }
-        return std::string();
     }
-    return formatSingleValue(values()[i]);
+    return result;
 }
 
 
@@ -440,32 +547,14 @@ void OptionStorageTemplate<T>::commitValues()
 {
     if (hasFlag(efOption_ClearOnNextSet))
     {
-        values_->swap(setValues_);
+        store_->clear();
     }
-    else
+    store_->reserve(setValues_.size());
+    for (T value : setValues_)
     {
-        values_->reserve(values_->size() + setValues_.size());
-        values_->insert(values_->end(), setValues_.begin(), setValues_.end());
+        store_->append(value);
     }
     clearSet();
-    refreshValues();
-}
-
-
-template <typename T>
-void OptionStorageTemplate<T>::refreshValues()
-{
-    if (countptr_ != NULL)
-    {
-        *countptr_ = static_cast<int>(values_->size());
-    }
-    if (store_ != NULL)
-    {
-        for (size_t i = 0; i < values_->size(); ++i)
-        {
-            store_[i] = (*values_)[i];
-        }
-    }
 }
 
 
@@ -479,12 +568,8 @@ void OptionStorageTemplate<T>::setDefaultValue(const T &value)
     if (hasFlag(efOption_HasDefaultValue))
     {
         setFlag(efOption_ExplicitDefaultValue);
-        clear();
-        clearSet();
-        addValue(value);
-        // TODO: As this is called from the constructor, it should not call
-        // virtual functions.
-        commitValues();
+        store_->clear();
+        store_->append(value);
     }
 }
 
index c9584dee9eceb29528793f81022848cd94cd2e2c..07397c888638019dde71300a9ae36326c9706dbb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2012,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2012,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -45,6 +45,7 @@
 
 #include "gromacs/options/abstractoptionstorage.h"
 #include "gromacs/options/options.h"
+#include "gromacs/options/optionsection.h"
 
 #include "options-impl.h"
 
@@ -69,17 +70,15 @@ void visitOption(OptionsModifyingVisitor *visitor, OptionInfo &optionInfo)
 
 //! Helper function to recursively visit all options in a group.
 template <class VisitorType>
-void acceptOptionsGroup(const OptionsImpl::Group &group, VisitorType *visitor)
+void acceptOptionsGroup(const internal::OptionSectionImpl::Group &group, VisitorType *visitor)
 {
-    OptionsImpl::Group::OptionList::const_iterator option;
-    for (option = group.options_.begin(); option != group.options_.end(); ++option)
+    for (const auto &option : group.options_)
     {
-        visitOption(visitor, (*option)->optionInfo());
+        visitOption(visitor, option->optionInfo());
     }
-    OptionsImpl::Group::SubgroupList::const_iterator subgroup;
-    for (subgroup = group.subgroups_.begin(); subgroup != group.subgroups_.end(); ++subgroup)
+    for (const auto &subgroup : group.subgroups_)
     {
-        acceptOptionsGroup(*subgroup, visitor);
+        acceptOptionsGroup(subgroup, visitor);
     }
 }
 
@@ -90,24 +89,26 @@ void acceptOptionsGroup(const OptionsImpl::Group &group, VisitorType *visitor)
  */
 
 OptionsIterator::OptionsIterator(const Options &options)
-    : options_(options)
+    : section_(options.rootSection().section())
 {
 }
 
-void OptionsIterator::acceptSubSections(OptionsVisitor *visitor) const
+OptionsIterator::OptionsIterator(const OptionSectionInfo &section)
+    : section_(section.section())
 {
-    const OptionsImpl::SubSectionList          &subSectionList =
-        options_.impl_->subSections_;
-    OptionsImpl::SubSectionList::const_iterator i;
-    for (i = subSectionList.begin(); i != subSectionList.end(); ++i)
+}
+
+void OptionsIterator::acceptSections(OptionsVisitor *visitor) const
+{
+    for (const auto &section : section_.subsections_)
     {
-        visitor->visitSubSection(*(*i));
+        visitor->visitSection(section->info());
     }
 }
 
 void OptionsIterator::acceptOptions(OptionsVisitor *visitor) const
 {
-    acceptOptionsGroup(options_.impl_->rootGroup_, visitor);
+    acceptOptionsGroup(section_.rootGroup_, visitor);
 }
 
 /********************************************************************
@@ -115,24 +116,26 @@ void OptionsIterator::acceptOptions(OptionsVisitor *visitor) const
  */
 
 OptionsModifyingIterator::OptionsModifyingIterator(Options *options)
-    : options_(*options)
+    : section_(options->rootSection().section())
+{
+}
+
+OptionsModifyingIterator::OptionsModifyingIterator(OptionSectionInfo *section)
+    : section_(section->section())
 {
 }
 
-void OptionsModifyingIterator::acceptSubSections(OptionsModifyingVisitor *visitor) const
+void OptionsModifyingIterator::acceptSections(OptionsModifyingVisitor *visitor) const
 {
-    const OptionsImpl::SubSectionList          &subSectionList =
-        options_.impl_->subSections_;
-    OptionsImpl::SubSectionList::const_iterator i;
-    for (i = subSectionList.begin(); i != subSectionList.end(); ++i)
+    for (auto &section : section_.subsections_)
     {
-        visitor->visitSubSection(*i);
+        visitor->visitSection(&section->info());
     }
 }
 
 void OptionsModifyingIterator::acceptOptions(OptionsModifyingVisitor *visitor) const
 {
-    acceptOptionsGroup(options_.impl_->rootGroup_, visitor);
+    acceptOptionsGroup(section_.rootGroup_, visitor);
 }
 
 } // namespace gmx
index 44e265a2f78dd4e3ffd1127d5306085a248e9fdf..6502f836b7524d7e1b49a90dac12cad34ee6d1a4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2014, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2014,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -54,6 +54,12 @@ namespace gmx
 {
 
 class Options;
+class OptionSectionInfo;
+
+namespace internal
+{
+class OptionSectionImpl;
+}
 
 /*! \libinternal \brief
  * Pure interface for visiting options in a Options object.
@@ -68,13 +74,9 @@ class OptionsVisitor
     public:
         virtual ~OptionsVisitor() {}
 
-        /*! \brief
-         * Called for each subsection in Options.
-         */
-        virtual void visitSubSection(const Options &section) = 0;
-        /*! \brief
-         * Called for each option in Options.
-         */
+        //! Called for each section.
+        virtual void visitSection(const OptionSectionInfo &section) = 0;
+        //! Called for each option.
         virtual void visitOption(const OptionInfo &option) = 0;
 };
 
@@ -93,7 +95,7 @@ class OptionsTypeVisitor : public OptionsVisitor
     public:
         virtual ~OptionsTypeVisitor() {}
 
-        virtual void visitSubSection(const Options &section) = 0;
+        virtual void visitSection(const OptionSectionInfo &section) = 0;
         /*! \brief
          * Called for each option of type \p InfoType.
          */
@@ -113,7 +115,7 @@ class OptionsTypeVisitor : public OptionsVisitor
 /*! \libinternal \brief
  * Decorator class for visiting options in a Options object.
  *
- * This class provides an interface for looping through subsections and
+ * This class provides an interface for looping through sections and
  * options in a Options object.
  *
  * Typical use (loop over all options, iteratively descending into
@@ -122,10 +124,10 @@ class OptionsTypeVisitor : public OptionsVisitor
    class Visitor : public gmx::OptionsVisitor
    {
        public:
-           void visitSubSection(const Options &section)
+           void visitSection(const Options &section)
            {
                OptionsIterator iterator(section);
-               iterator.acceptSubSections(this);
+               iterator.acceptSections(this);
                iterator.acceptOptions(this);
            }
 
@@ -135,7 +137,7 @@ class OptionsTypeVisitor : public OptionsVisitor
            }
    }
 
-   Visitor().visitSubSection(options);
+   Visitor().visitSection(options);
  * \endcode
  *
  * \inlibraryapi
@@ -146,21 +148,22 @@ class OptionsIterator
     public:
         /*! \brief
          * Creates an object for visiting options in a Options object.
+         *
+         * The created iterator iterates over the "root" section in the Options
+         * object.
          */
         explicit OptionsIterator(const Options &options);
+        //! Creates an object for visiting options in an options section.
+        explicit OptionsIterator(const OptionSectionInfo &section);
 
-        /*! \brief
-         * Visits each subsection in the wrapped Options object.
-         */
-        void acceptSubSections(OptionsVisitor *visitor) const;
-        /*! \brief
-         * Visits each option in the wrapped Options object.
-         */
+        //! Visits each section in the wrapped section.
+        void acceptSections(OptionsVisitor *visitor) const;
+        //! Visits each option in the wrapped section.
         void acceptOptions(OptionsVisitor *visitor) const;
 
     private:
-        //! The wrapped Options object.
-        const Options          &options_;
+        //! The wrapped section object.
+        const internal::OptionSectionImpl &section_;
 
         GMX_DISALLOW_COPY_AND_ASSIGN(OptionsIterator);
 };
@@ -179,13 +182,9 @@ class OptionsModifyingVisitor
     public:
         virtual ~OptionsModifyingVisitor() {}
 
-        /*! \brief
-         * Called for each subsection in Options.
-         */
-        virtual void visitSubSection(Options *section) = 0;
-        /*! \brief
-         * Called for each option in Options.
-         */
+        //! Called for each section.
+        virtual void visitSection(OptionSectionInfo *section) = 0;
+        //! Called for each option.
         virtual void visitOption(OptionInfo *option) = 0;
 };
 
@@ -205,7 +204,7 @@ class OptionsModifyingTypeVisitor : public OptionsModifyingVisitor
     public:
         virtual ~OptionsModifyingTypeVisitor() {}
 
-        virtual void visitSubSection(Options *section) = 0;
+        virtual void visitSection(OptionSectionInfo *section) = 0;
         /*! \brief
          * Called for each option of type \p InfoType.
          */
@@ -238,21 +237,22 @@ class OptionsModifyingIterator
     public:
         /*! \brief
          * Creates an object for visiting options in a Options object.
+         *
+         * The created iterator iterates over the "root" section in the Options
+         * object.
          */
         explicit OptionsModifyingIterator(Options *options);
+        //! Creates an object for visiting options in an options section.
+        explicit OptionsModifyingIterator(OptionSectionInfo *section);
 
-        /*! \brief
-         * Visits each subsection in the wrapped Options object.
-         */
-        void acceptSubSections(OptionsModifyingVisitor *visitor) const;
-        /*! \brief
-         * Visits each option in the wrapped Options object.
-         */
+        //! Visits each section in the wrapped section.
+        void acceptSections(OptionsModifyingVisitor *visitor) const;
+        //! Visits each option in the wrapped section.
         void acceptOptions(OptionsModifyingVisitor *visitor) const;
 
     private:
-        //! The wrapped Options object.
-        Options                &options_;
+        //! The wrapped section object.
+        internal::OptionSectionImpl &section_;
 
         GMX_DISALLOW_COPY_AND_ASSIGN(OptionsModifyingIterator);
 };
diff --git a/src/gromacs/options/repeatingsection.h b/src/gromacs/options/repeatingsection.h
new file mode 100644 (file)
index 0000000..683a41a
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \file
+ * \brief
+ * Declares gmx::RepeatingOptionSection and related classes.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inpublicapi
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_REPEATINGSECTION_H
+#define GMX_OPTIONS_REPEATINGSECTION_H
+
+#include <memory>
+#include <vector>
+
+#include "gromacs/options/abstractsection.h"
+#include "gromacs/options/ioptionscontainerwithsections.h"
+#include "gromacs/options/isectionstorage.h"
+#include "gromacs/options/valuestore.h"
+
+namespace gmx
+{
+
+template <class T> class RepeatingOptionSectionHandle;
+template <class T> class RepeatingOptionSectionStorage;
+
+/*! \brief
+ * Declares an option section that creates a structure for each instance.
+ *
+ * \tparam  T  Structure that stores the values for an instance of the section.
+ *
+ * This class declares a section that can be specified multiple times, and
+ * creates an instance of `T` for each instance.  Options within the section
+ * can store their values in the created structure.
+ *
+ * \inpublicapi
+ * \ingroup module_options
+ */
+template <class T>
+class RepeatingOptionSection : public AbstractOptionSection
+{
+    public:
+        //! AbstractOptionSectionHandle corresponding to this option type.
+        typedef RepeatingOptionSectionHandle<T> HandleType;
+
+        //! Creates a section with the given name.
+        explicit RepeatingOptionSection(const char *name)
+            : AbstractOptionSection(name), values_(nullptr)
+        {
+        }
+
+        //! Specifies a vector to receive the section structures.
+        RepeatingOptionSection &storeVector(std::vector<T> *values)
+        {
+            values_ = values;
+            return *this;
+        }
+
+    private:
+        virtual IOptionSectionStorage *createStorage() const;
+
+        std::vector<T> *values_;
+
+        //! Allows accessing the properties when initializing the storage.
+        friend class RepeatingOptionSectionStorage<T>;
+};
+
+/*! \internal
+ * \brief
+ * Implements handling of the structures that stores per-section values.
+ *
+ * \ingroup module_options
+ */
+template <class T>
+class RepeatingOptionSectionStorage : public IOptionSectionStorage
+{
+    public:
+        //! Initializes the storage for given section properties.
+        explicit RepeatingOptionSectionStorage(const RepeatingOptionSection<T> &section)
+            : store_(new OptionValueStoreVector<T>(section.values_)), currentData_()
+        {
+        }
+
+        virtual void initStorage()
+        {
+            defaultValues_ = currentData_;
+        }
+        virtual void startSection()
+        {
+            resetSection();
+        }
+        virtual void finishSection()
+        {
+            store_->append(currentData_);
+            resetSection();
+        }
+
+    private:
+        void resetSection()
+        {
+            currentData_ = defaultValues_;
+        }
+
+        //! Final storage location for the section structures.
+        const std::unique_ptr<IOptionValueStore<T> > store_;
+        T                                            defaultValues_;
+        /*! \brief
+         * Stores the values for the current in-process section.
+         *
+         * Options within the section store their values to this structure, and
+         * they are then copied to the final storage when the section finishes.
+         */
+        T                                            currentData_;
+
+        //! Allows binding option storage to the current section data structure.
+        friend class RepeatingOptionSectionHandle<T>;
+};
+
+template <class T>
+IOptionSectionStorage *RepeatingOptionSection<T>::createStorage() const
+{
+    return new RepeatingOptionSectionStorage<T>(*this);
+}
+
+/*! \brief
+ * Allows adding options to an RepeatingOptionSection.
+ *
+ * An instance of this class is returned from
+ * IOptionsContainerWithSections::addSection(), and supports adding options and
+ * subsections to a section created with OptionSection.
+ *
+ * Example:
+ * \code
+   struct SectionData { int value; }
+   // as class attribute
+   std::vector<SectionData> values;
+
+   void MyClass::initOptions(gmx::IOptionsContainerWithSections *options)
+   {
+       auto sec = options->addSection(gmx::RepeatingOptionSection<SectionData>("sec").storeVector(&values));
+       sec->addOption(gmx::IntegerOption("arg").store(&sec.bind().value));
+   }
+   \endcode
+ *
+ * \inpublicapi
+ * \ingroup module_options
+ */
+template <class T>
+class RepeatingOptionSectionHandle : public AbstractOptionSectionHandle
+{
+    public:
+        //! Wraps a given section storage object.
+        explicit RepeatingOptionSectionHandle(internal::OptionSectionImpl *section)
+            : AbstractOptionSectionHandle(section),
+              storage_(getStorage<RepeatingOptionSectionStorage<T> >(section))
+        {
+        }
+
+        /*! \brief
+         * Supports storing option values within the per-section data structure.
+         *
+         * See class documentation for an example.
+         */
+        T &bind()
+        {
+            return storage_->currentData_;
+        }
+
+    private:
+        RepeatingOptionSectionStorage<T> *storage_;
+};
+
+} // namespace gmx
+
+#endif
index 21806d0aed9d027c61fbd37d476f7336763d8f89..e99c2a97750dff81e3e373d85cc5b80eeda24715 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2010,2011,2012,2014, by the GROMACS development team, led by
+# Copyright (c) 2010,2011,2012,2014,2016, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -38,4 +38,7 @@ gmx_add_unit_test(OptionsUnitTests options-test
                   filenameoptionmanager.cpp
                   option.cpp
                   optionsassigner.cpp
-                  timeunitmanager.cpp)
+                  repeatingsection.cpp
+                  timeunitmanager.cpp
+                  treesupport.cpp
+                  )
index 1682129575a0eec6f53c8cd1fd2ef746797d64d5..1cfab3a8a6eb4de64dad1519d15bc823744da804 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -90,7 +90,7 @@ class MockOptionStorage : public gmx::OptionStorageTemplate<std::string>
          *
          * \param[in] settings   Storage settings.
          */
-        MockOptionStorage(const MockOption &settings);
+        explicit MockOptionStorage(const MockOption &settings);
 
         /*! \brief
          * Calls addValue("dummy") in the base class.
@@ -99,25 +99,9 @@ class MockOptionStorage : public gmx::OptionStorageTemplate<std::string>
         {
             addValue("dummy");
         }
-        // using MyBase::markAsSet;
-        // using MyBase::addValue;
-        // using MyBase::commitValues;
-        // "using" is correct but MSVC gives error C2248. Workaround:
-        //! \copydoc gmx::OptionStorageTemplate::markAsSet()
-        void markAsSet()
-        {
-            MyBase::markAsSet();
-        }
-        //! \copydoc gmx::OptionStorageTemplate::addValue()
-        void addValue(const std::string &value)
-        {
-            MyBase::addValue(value);
-        }
-        //! \copydoc gmx::OptionStorageTemplate::commitValues()
-        void commitValues()
-        {
-            MyBase::commitValues();
-        }
+        using MyBase::markAsSet;
+        using MyBase::addValue;
+        using MyBase::commitValues;
 
         virtual gmx::OptionInfo &optionInfo() { return info_; }
         // These are not used.
@@ -126,6 +110,16 @@ class MockOptionStorage : public gmx::OptionStorageTemplate<std::string>
         {
             return "";
         }
+        virtual std::vector<gmx::Variant>
+        normalizeValues(const std::vector<gmx::Variant> &values) const
+        {
+            return values;
+        }
+
+        virtual void convertValue(const gmx::Variant &value)
+        {
+            convertValue(value.cast<std::string>());
+        }
 
         MOCK_METHOD1(convertValue, void(const std::string &value));
         MOCK_METHOD1(processSetValues, void(ValueList *values));
@@ -186,7 +180,7 @@ MockOptionStorage &MockOptionInfo::option()
  */
 TEST(AbstractOptionStorageTest, HandlesSetInFinish)
 {
-    gmx::Options                options(NULL, NULL);
+    gmx::Options                options;
     std::vector<std::string>    values;
     MockOptionInfo             *info = options.addOption(
                 MockOption("name").required().storeVector(&values));
@@ -216,7 +210,7 @@ TEST(AbstractOptionStorageTest, HandlesSetInFinish)
  */
 TEST(AbstractOptionStorageTest, HandlesValueRemoval)
 {
-    gmx::Options                options(NULL, NULL);
+    gmx::Options                options;
     std::vector<std::string>    values;
     MockOptionInfo             *info = options.addOption(
                 MockOption("name").storeVector(&values).multiValue());
@@ -255,7 +249,7 @@ TEST(AbstractOptionStorageTest, HandlesValueRemoval)
  */
 TEST(AbstractOptionStorageTest, HandlesValueAddition)
 {
-    gmx::Options                options(NULL, NULL);
+    gmx::Options                options;
     std::vector<std::string>    values;
     MockOptionInfo             *info = options.addOption(
                 MockOption("name").storeVector(&values).multiValue());
@@ -295,7 +289,7 @@ TEST(AbstractOptionStorageTest, HandlesValueAddition)
  */
 TEST(AbstractOptionStorageTest, HandlesTooManyValueAddition)
 {
-    gmx::Options                options(NULL, NULL);
+    gmx::Options                options;
     std::vector<std::string>    values;
     MockOptionInfo             *info = options.addOption(
                 MockOption("name").storeVector(&values).valueCount(2));
@@ -331,7 +325,7 @@ TEST(AbstractOptionStorageTest, HandlesTooManyValueAddition)
  */
 TEST(AbstractOptionStorageTest, AllowsEmptyValues)
 {
-    gmx::Options                options(NULL, NULL);
+    gmx::Options                options;
     std::vector<std::string>    values;
     MockOptionInfo             *info = options.addOption(
                 MockOption("name").storeVector(&values).valueCount(0));
index 5ae358f3cbb3044d3d1a702599ffa5bb3ab3a37b..2d3cde55f528c945ba9e2f3041192148e04eaa13 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -59,7 +59,7 @@ using gmx::FileNameOption;
 
 TEST(FileNameOptionTest, HandlesRequiredDefaultValueWithoutExtension)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     ASSERT_NO_THROW_GMX(options.addOption(
                                 FileNameOption("f").store(&value).required()
@@ -77,7 +77,7 @@ TEST(FileNameOptionTest, HandlesRequiredDefaultValueWithoutExtension)
 
 TEST(FileNameOptionTest, HandlesRequiredOptionWithoutValue)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     ASSERT_NO_THROW_GMX(options.addOption(
                                 FileNameOption("f").store(&value).required()
@@ -97,7 +97,7 @@ TEST(FileNameOptionTest, HandlesRequiredOptionWithoutValue)
 
 TEST(FileNameOptionTest, HandlesOptionalUnsetOption)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     ASSERT_NO_THROW_GMX(options.addOption(
                                 FileNameOption("f").store(&value)
@@ -115,7 +115,7 @@ TEST(FileNameOptionTest, HandlesOptionalUnsetOption)
 
 TEST(FileNameOptionTest, HandlesOptionalDefaultValueWithoutExtension)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     ASSERT_NO_THROW_GMX(options.addOption(
                                 FileNameOption("f").store(&value)
@@ -135,7 +135,7 @@ TEST(FileNameOptionTest, HandlesOptionalDefaultValueWithoutExtension)
 
 TEST(FileNameOptionTest, HandlesRequiredCustomDefaultExtension)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     ASSERT_NO_THROW_GMX(options.addOption(
                                 FileNameOption("f").store(&value).required()
@@ -154,7 +154,7 @@ TEST(FileNameOptionTest, HandlesRequiredCustomDefaultExtension)
 
 TEST(FileNameOptionTest, HandlesOptionalCustomDefaultExtension)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     ASSERT_NO_THROW_GMX(options.addOption(
                                 FileNameOption("f").store(&value)
@@ -175,7 +175,7 @@ TEST(FileNameOptionTest, HandlesOptionalCustomDefaultExtension)
 
 TEST(FileNameOptionTest, GivesErrorOnUnknownFileSuffix)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     ASSERT_NO_THROW_GMX(options.addOption(
                                 FileNameOption("f").store(&value)
@@ -195,7 +195,7 @@ TEST(FileNameOptionTest, GivesErrorOnUnknownFileSuffix)
 
 TEST(FileNameOptionTest, GivesErrorOnInvalidFileSuffix)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     ASSERT_NO_THROW_GMX(options.addOption(
                                 FileNameOption("f").store(&value)
index 6992689febcd245d5730cb8b3ad2e0cc31e6fa15..9a67461c05ebf87065b4c9fbd8bec1fe28ac50b4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -63,7 +63,6 @@ class FileNameOptionManagerTest : public ::testing::Test
 {
     public:
         FileNameOptionManagerTest()
-            : options_(NULL, NULL)
         {
             manager_.setInputRedirector(&redirector_);
             options_.addManager(&manager_);
index 5d6cf976b66e85be1c1eb2cbc8969b402a1b4a76..c9d85b2b9bb223d5c7a9c60117e5c0119559bfa4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -60,7 +60,7 @@ namespace
 
 TEST(OptionsTest, FailsOnNonsafeStorage)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value = -1;
     using gmx::IntegerOption;
     ASSERT_THROW_GMX(options.addOption(IntegerOption("name").store(&value)
index b9dd8eb5f8f77a7581388e1ad97bb74d29fd0c33..e13a17ecdb631438bf03b7d6093f7b7ad97ddc0e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 
 #include "gromacs/options/basicoptions.h"
 #include "gromacs/options/options.h"
+#include "gromacs/options/optionsection.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/stringutil.h"
+#include "gromacs/utility/variant.h"
 
 #include "testutils/testasserts.h"
 
@@ -70,7 +72,7 @@ namespace
 
 TEST(OptionsAssignerTest, HandlesMissingRequiredParameter)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value = 0;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(
@@ -81,7 +83,7 @@ TEST(OptionsAssignerTest, HandlesMissingRequiredParameter)
 
 TEST(OptionsAssignerTest, HandlesRequiredParameterWithDefaultValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value = 0;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(
@@ -94,7 +96,7 @@ TEST(OptionsAssignerTest, HandlesRequiredParameterWithDefaultValue)
 
 TEST(OptionsAssignerTest, HandlesInvalidMultipleParameter)
 {
-    gmx::Options     options(NULL, NULL);
+    gmx::Options     options;
     std::vector<int> values;
     bool             bIsSet = false;
     using gmx::IntegerOption;
@@ -119,7 +121,7 @@ TEST(OptionsAssignerTest, HandlesInvalidMultipleParameter)
 
 TEST(OptionsAssignerTest, HandlesMultipleParameter)
 {
-    gmx::Options     options(NULL, NULL);
+    gmx::Options     options;
     std::vector<int> values;
     bool             bIsSet = false;
     using gmx::IntegerOption;
@@ -147,7 +149,7 @@ TEST(OptionsAssignerTest, HandlesMultipleParameter)
 
 TEST(OptionsAssignerTest, HandlesMissingValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value1 = 0, value2 = 0;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value1)));
@@ -168,7 +170,7 @@ TEST(OptionsAssignerTest, HandlesMissingValue)
 
 TEST(OptionsAssignerTest, HandlesExtraValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value1 = 0;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value1)));
@@ -187,7 +189,7 @@ TEST(OptionsAssignerTest, HandlesExtraValue)
 
 TEST(OptionsAssignerTest, HandlesGroups)
 {
-    gmx::Options            options(NULL, NULL);
+    gmx::Options            options;
     gmx::IOptionsContainer &group1 = options.addGroup();
     gmx::IOptionsContainer &group2 = options.addGroup();
     int                     value  = 3;
@@ -217,36 +219,35 @@ TEST(OptionsAssignerTest, HandlesGroups)
     EXPECT_EQ(6, value2);
 }
 
-TEST(OptionsAssignerTest, HandlesSubSections)
+TEST(OptionsAssignerTest, HandlesSections)
 {
-    gmx::Options options(NULL, NULL);
-    gmx::Options sub1("section1", NULL);
-    gmx::Options sub2("section2", NULL);
+    using gmx::OptionSection;
+    gmx::Options options;
+    auto         sub1   = options.addSection(OptionSection("section1"));
+    auto         sub2   = options.addSection(OptionSection("section2"));
     int          value  = 3;
     int          value1 = 1;
     int          value2 = 2;
     using gmx::IntegerOption;
-    ASSERT_NO_THROW(options.addSubSection(&sub1));
-    ASSERT_NO_THROW(options.addSubSection(&sub2));
-    ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
-    ASSERT_NO_THROW(sub1.addOption(IntegerOption("p").store(&value1)));
-    ASSERT_NO_THROW(sub2.addOption(IntegerOption("p").store(&value2)));
+    ASSERT_NO_THROW_GMX(options.addOption(IntegerOption("p").store(&value)));
+    ASSERT_NO_THROW_GMX(sub1.addOption(IntegerOption("p").store(&value1)));
+    ASSERT_NO_THROW_GMX(sub2.addOption(IntegerOption("p").store(&value2)));
 
     gmx::OptionsAssigner assigner(&options);
     EXPECT_NO_THROW(assigner.start());
-    ASSERT_NO_THROW(assigner.startSubSection("section1"));
+    ASSERT_NO_THROW(assigner.startSection("section1"));
     ASSERT_NO_THROW(assigner.startOption("p"));
     EXPECT_NO_THROW(assigner.appendValue("5"));
     EXPECT_NO_THROW(assigner.finishOption());
-    EXPECT_NO_THROW(assigner.finishSubSection());
+    EXPECT_NO_THROW(assigner.finishSection());
     ASSERT_NO_THROW(assigner.startOption("p"));
     EXPECT_NO_THROW(assigner.appendValue("4"));
     EXPECT_NO_THROW(assigner.finishOption());
-    ASSERT_NO_THROW(assigner.startSubSection("section2"));
+    ASSERT_NO_THROW(assigner.startSection("section2"));
     ASSERT_NO_THROW(assigner.startOption("p"));
     EXPECT_NO_THROW(assigner.appendValue("6"));
     EXPECT_NO_THROW(assigner.finishOption());
-    EXPECT_NO_THROW(assigner.finishSubSection());
+    EXPECT_NO_THROW(assigner.finishSection());
     EXPECT_NO_THROW(assigner.finish());
     EXPECT_NO_THROW(options.finish());
 
@@ -257,7 +258,7 @@ TEST(OptionsAssignerTest, HandlesSubSections)
 
 TEST(OptionsAssignerTest, HandlesMultipleSources)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value = -1;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
@@ -290,7 +291,7 @@ TEST(OptionsAssignerTest, HandlesMultipleSources)
 
 TEST(OptionsAssignerBooleanTest, StoresYesValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     bool         value = false;
     using gmx::BooleanOption;
     ASSERT_NO_THROW(options.addOption(BooleanOption("p").store(&value)));
@@ -308,7 +309,7 @@ TEST(OptionsAssignerBooleanTest, StoresYesValue)
 
 TEST(OptionsAssignerBooleanTest, SetsBooleanWithoutExplicitValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     bool         value = false;
     using gmx::BooleanOption;
     ASSERT_NO_THROW(options.addOption(BooleanOption("p").store(&value)));
@@ -325,7 +326,7 @@ TEST(OptionsAssignerBooleanTest, SetsBooleanWithoutExplicitValue)
 
 TEST(OptionsAssignerBooleanTest, ClearsBooleanWithPrefixNo)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     bool         value = true;
     using gmx::BooleanOption;
     ASSERT_NO_THROW(options.addOption(BooleanOption("p").store(&value)));
@@ -343,7 +344,7 @@ TEST(OptionsAssignerBooleanTest, ClearsBooleanWithPrefixNo)
 
 TEST(OptionsAssignerBooleanTest, HandlesBooleanWithPrefixAndValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     bool         value = false;
     using gmx::BooleanOption;
     ASSERT_NO_THROW(options.addOption(BooleanOption("p").store(&value)));
@@ -374,7 +375,7 @@ TEST(OptionsAssignerBooleanTest, HandlesBooleanWithPrefixAndValue)
 
 TEST(OptionsAssignerIntegerTest, StoresSingleValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value = 1;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
@@ -392,7 +393,7 @@ TEST(OptionsAssignerIntegerTest, StoresSingleValue)
 
 TEST(OptionsAssignerIntegerTest, HandlesEmptyValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value = 1;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
@@ -410,7 +411,7 @@ TEST(OptionsAssignerIntegerTest, HandlesEmptyValue)
 
 TEST(OptionsAssignerIntegerTest, HandlesInvalidValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value = 1;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
@@ -428,7 +429,7 @@ TEST(OptionsAssignerIntegerTest, HandlesInvalidValue)
 
 TEST(OptionsAssignerIntegerTest, HandlesOverflow)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value = 1;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
@@ -448,7 +449,7 @@ TEST(OptionsAssignerIntegerTest, HandlesOverflow)
 
 TEST(OptionsAssignerIntegerTest, StoresDefaultValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value = -1;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(
@@ -465,7 +466,7 @@ TEST(OptionsAssignerIntegerTest, StoresDefaultValue)
 
 TEST(OptionsAssignerIntegerTest, StoresDefaultValueIfSet)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value = -1;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(
@@ -484,7 +485,7 @@ TEST(OptionsAssignerIntegerTest, StoresDefaultValueIfSet)
 
 TEST(OptionsAssignerIntegerTest, HandlesDefaultValueIfSetWhenNotSet)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value = -1;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(
@@ -501,7 +502,7 @@ TEST(OptionsAssignerIntegerTest, HandlesDefaultValueIfSetWhenNotSet)
 
 TEST(OptionsAssignerIntegerTest, HandlesBothDefaultValues)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value = -1;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(
@@ -521,7 +522,7 @@ TEST(OptionsAssignerIntegerTest, HandlesBothDefaultValues)
 
 TEST(OptionsAssignerIntegerTest, StoresToVector)
 {
-    gmx::Options          options(NULL, NULL);
+    gmx::Options          options;
     std::vector<int>      values;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(
@@ -545,7 +546,7 @@ TEST(OptionsAssignerIntegerTest, StoresToVector)
 
 TEST(OptionsAssignerIntegerTest, HandlesVectors)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          vec[3] = {0, 0, 0};
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(vec).vector()));
@@ -567,7 +568,7 @@ TEST(OptionsAssignerIntegerTest, HandlesVectors)
 
 TEST(OptionsAssignerIntegerTest, HandlesVectorFromSingleValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          vec[3] = {0, 0, 0};
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(vec).vector()));
@@ -587,7 +588,7 @@ TEST(OptionsAssignerIntegerTest, HandlesVectorFromSingleValue)
 
 TEST(OptionsAssignerIntegerTest, HandlesVectorsWithDefaultValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          vec[3] = {3, 2, 1};
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(vec).vector()));
@@ -601,12 +602,10 @@ TEST(OptionsAssignerIntegerTest, HandlesVectorsWithDefaultValue)
 
 TEST(OptionsAssignerIntegerTest, HandlesVectorsWithDefaultValueWithInvalidAssignment)
 {
-    gmx::Options     options(NULL, NULL);
+    gmx::Options     options;
     int              vec[3] = {3, 2, 1};
-    std::vector<int> vec2(vec, vec+3);
     using gmx::IntegerOption;
-    ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(vec)
-                                          .storeVector(&vec2).vector()));
+    ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(vec).vector()));
 
     gmx::OptionsAssigner assigner(&options);
     EXPECT_NO_THROW(assigner.start());
@@ -620,10 +619,6 @@ TEST(OptionsAssignerIntegerTest, HandlesVectorsWithDefaultValueWithInvalidAssign
     EXPECT_EQ(3, vec[0]);
     EXPECT_EQ(2, vec[1]);
     EXPECT_EQ(1, vec[2]);
-    ASSERT_EQ(3U, vec2.size());
-    EXPECT_EQ(3, vec2[0]);
-    EXPECT_EQ(2, vec2[1]);
-    EXPECT_EQ(1, vec2[2]);
 }
 
 
@@ -633,7 +628,7 @@ TEST(OptionsAssignerIntegerTest, HandlesVectorsWithDefaultValueWithInvalidAssign
 
 TEST(OptionsAssignerDoubleTest, StoresSingleValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     double       value = 0.0;
     using gmx::DoubleOption;
     ASSERT_NO_THROW(options.addOption(DoubleOption("p").store(&value)));
@@ -649,9 +644,27 @@ TEST(OptionsAssignerDoubleTest, StoresSingleValue)
     EXPECT_DOUBLE_EQ(2.7, value);
 }
 
+TEST(OptionsAssignerDoubleTest, StoresValueFromFloat)
+{
+    gmx::Options options;
+    double       value = 0.0;
+    using gmx::DoubleOption;
+    ASSERT_NO_THROW(options.addOption(DoubleOption("p").store(&value)));
+
+    gmx::OptionsAssigner assigner(&options);
+    EXPECT_NO_THROW(assigner.start());
+    ASSERT_NO_THROW(assigner.startOption("p"));
+    ASSERT_NO_THROW(assigner.appendValue(gmx::Variant::create<float>(2.7)));
+    EXPECT_NO_THROW(assigner.finishOption());
+    EXPECT_NO_THROW(assigner.finish());
+    EXPECT_NO_THROW(options.finish());
+
+    EXPECT_FLOAT_EQ(2.7, value);
+}
+
 TEST(OptionsAssignerDoubleTest, HandlesEmptyValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     double       value = 1.0;
     using gmx::DoubleOption;
     ASSERT_NO_THROW(options.addOption(DoubleOption("p").store(&value)));
@@ -667,6 +680,44 @@ TEST(OptionsAssignerDoubleTest, HandlesEmptyValue)
     EXPECT_DOUBLE_EQ(1.0, value);
 }
 
+TEST(OptionsAssignerDoubleTest, HandlesPreSetScaleValue)
+{
+    gmx::Options           options;
+    double                 value = 1.0;
+    using gmx::DoubleOption;
+    gmx::DoubleOptionInfo *info = options.addOption(DoubleOption("p").store(&value));
+    EXPECT_NO_THROW(info->setScaleFactor(10));
+
+    gmx::OptionsAssigner assigner(&options);
+    EXPECT_NO_THROW(assigner.start());
+    ASSERT_NO_THROW(assigner.startOption("p"));
+    ASSERT_NO_THROW(assigner.appendValue("2.7"));
+    EXPECT_NO_THROW(assigner.finishOption());
+    EXPECT_NO_THROW(assigner.finish());
+    EXPECT_NO_THROW(options.finish());
+
+    EXPECT_DOUBLE_EQ(27, value);
+}
+
+TEST(OptionsAssignerDoubleTest, HandlesPostSetScaleValue)
+{
+    gmx::Options           options;
+    double                 value = 1.0;
+    using gmx::DoubleOption;
+    gmx::DoubleOptionInfo *info = options.addOption(DoubleOption("p").store(&value));
+
+    gmx::OptionsAssigner   assigner(&options);
+    EXPECT_NO_THROW(assigner.start());
+    ASSERT_NO_THROW(assigner.startOption("p"));
+    ASSERT_NO_THROW(assigner.appendValue("2.7"));
+    EXPECT_NO_THROW(assigner.finishOption());
+    EXPECT_NO_THROW(assigner.finish());
+    EXPECT_NO_THROW(info->setScaleFactor(10));
+    EXPECT_NO_THROW(options.finish());
+
+    EXPECT_DOUBLE_EQ(27, value);
+}
+
 
 /********************************************************************
  * Tests for string assignment
@@ -677,7 +728,7 @@ const char *const c_allowed[] = { "none", "test", "value" };
 
 TEST(OptionsAssignerStringTest, StoresSingleValue)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     using gmx::StringOption;
     ASSERT_NO_THROW(options.addOption(StringOption("p").store(&value)));
@@ -695,7 +746,7 @@ TEST(OptionsAssignerStringTest, StoresSingleValue)
 
 TEST(OptionsAssignerStringTest, HandlesEnumValue)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     using gmx::StringOption;
     ASSERT_NO_THROW(options.addOption(
@@ -715,7 +766,7 @@ TEST(OptionsAssignerStringTest, HandlesEnumValue)
 
 TEST(OptionsAssignerStringTest, HandlesEnumValueFromNullTerminatedArray)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     const char * const     allowed[] = { "none", "test", "value", NULL };
     using gmx::StringOption;
@@ -736,7 +787,7 @@ TEST(OptionsAssignerStringTest, HandlesEnumValueFromNullTerminatedArray)
 
 TEST(OptionsAssignerStringTest, HandlesIncorrectEnumValue)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     using gmx::StringOption;
     ASSERT_NO_THROW(options.addOption(
@@ -751,7 +802,7 @@ TEST(OptionsAssignerStringTest, HandlesIncorrectEnumValue)
 
 TEST(OptionsAssignerStringTest, CompletesEnumValue)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     using gmx::StringOption;
     ASSERT_NO_THROW(options.addOption(
@@ -771,7 +822,7 @@ TEST(OptionsAssignerStringTest, CompletesEnumValue)
 
 TEST(OptionsAssignerStringTest, HandlesEnumWithNoValue)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     using gmx::StringOption;
     ASSERT_NO_THROW(options.addOption(
@@ -786,7 +837,7 @@ TEST(OptionsAssignerStringTest, HandlesEnumWithNoValue)
 
 TEST(OptionsAssignerStringTest, HandlesEnumDefaultValue)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     using gmx::StringOption;
     ASSERT_NO_THROW(options.addOption(
@@ -804,7 +855,7 @@ TEST(OptionsAssignerStringTest, HandlesEnumDefaultValue)
 
 TEST(OptionsAssignerStringTest, HandlesEnumDefaultValueFromVariable)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value("test");
     using gmx::StringOption;
     ASSERT_NO_THROW(options.addOption(
@@ -822,10 +873,10 @@ TEST(OptionsAssignerStringTest, HandlesEnumDefaultValueFromVariable)
 
 TEST(OptionsAssignerStringTest, HandlesEnumDefaultValueFromVector)
 {
-    gmx::Options             options(NULL, NULL);
+    gmx::Options             options;
     std::vector<std::string> value;
-    value.push_back("test");
-    value.push_back("value");
+    value.emplace_back("test");
+    value.emplace_back("value");
     using gmx::StringOption;
     ASSERT_NO_THROW(options.addOption(
                             StringOption("p").storeVector(&value).valueCount(2)
@@ -860,7 +911,7 @@ enum TestEnum
 
 TEST(OptionsAssignerEnumTest, StoresSingleValue)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     TestEnum               value     = etestNone;
     using gmx::EnumOption;
     ASSERT_NO_THROW(options.addOption(
@@ -881,7 +932,7 @@ TEST(OptionsAssignerEnumTest, StoresSingleValue)
 
 TEST(OptionsAssignerEnumTest, StoresVectorValues)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::vector<TestEnum>  values;
     using gmx::EnumOption;
     ASSERT_NO_THROW(options.addOption(
@@ -905,7 +956,7 @@ TEST(OptionsAssignerEnumTest, StoresVectorValues)
 
 TEST(OptionsAssignerEnumTest, HandlesInitialValueOutOfRange)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     TestEnum               value     = etestNR;
     using gmx::EnumOption;
     ASSERT_NO_THROW(options.addOption(
@@ -923,7 +974,7 @@ TEST(OptionsAssignerEnumTest, HandlesInitialValueOutOfRange)
 
 TEST(OptionsAssignerEnumTest, HandlesEnumDefaultValue)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     TestEnum               value     = etestNone;
     using gmx::EnumOption;
     ASSERT_NO_THROW(options.addOption(
@@ -941,7 +992,7 @@ TEST(OptionsAssignerEnumTest, HandlesEnumDefaultValue)
 
 TEST(OptionsAssignerEnumTest, HandlesEnumDefaultValueFromVariable)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     TestEnum               value     = etestTest;
     using gmx::EnumOption;
     ASSERT_NO_THROW(options.addOption(
@@ -959,7 +1010,7 @@ TEST(OptionsAssignerEnumTest, HandlesEnumDefaultValueFromVariable)
 
 TEST(OptionsAssignerEnumTest, HandlesEnumDefaultValueFromVector)
 {
-    gmx::Options             options(NULL, NULL);
+    gmx::Options             options;
     std::vector<TestEnum>    value;
     value.push_back(etestNone);
     value.push_back(etestTest);
diff --git a/src/gromacs/options/tests/refdata/TreeValueSupportAdjustTest_FillsDefaultObjectValues.xml b/src/gromacs/options/tests/refdata/TreeValueSupportAdjustTest_FillsDefaultObjectValues.xml
new file mode 100644 (file)
index 0000000..4799fb4
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Object Name="Input"></Object>
+  <Object Name="Output">
+    <Int Name="a">3</Int>
+    <Object Name="s">
+      <Int Name="a">1</Int>
+    </Object>
+    <Object Name="r">
+      <Int Name="a">2</Int>
+    </Object>
+  </Object>
+</ReferenceData>
diff --git a/src/gromacs/options/tests/refdata/TreeValueSupportAdjustTest_FillsDefaultValues.xml b/src/gromacs/options/tests/refdata/TreeValueSupportAdjustTest_FillsDefaultValues.xml
new file mode 100644 (file)
index 0000000..62f1caf
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Object Name="Input"></Object>
+  <Object Name="Output">
+    <Int Name="a">2</Int>
+  </Object>
+</ReferenceData>
diff --git a/src/gromacs/options/tests/refdata/TreeValueSupportAdjustTest_FillsDefaultVectorValues.xml b/src/gromacs/options/tests/refdata/TreeValueSupportAdjustTest_FillsDefaultVectorValues.xml
new file mode 100644 (file)
index 0000000..4f6ee6a
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Object Name="Input"></Object>
+  <Object Name="Output">
+    <Sequence Name="a">
+      <Int Name="Length">3</Int>
+      <Int>1</Int>
+      <Int>2</Int>
+      <Int>3</Int>
+    </Sequence>
+  </Object>
+</ReferenceData>
diff --git a/src/gromacs/options/tests/refdata/TreeValueSupportAdjustTest_MergesDefaultValues.xml b/src/gromacs/options/tests/refdata/TreeValueSupportAdjustTest_MergesDefaultValues.xml
new file mode 100644 (file)
index 0000000..0640b73
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Object Name="Input">
+    <Int Name="b">1</Int>
+  </Object>
+  <Object Name="Output">
+    <Int Name="a">2</Int>
+    <Int Name="b">1</Int>
+  </Object>
+</ReferenceData>
diff --git a/src/gromacs/options/tests/refdata/TreeValueSupportAdjustTest_NormalizesValues.xml b/src/gromacs/options/tests/refdata/TreeValueSupportAdjustTest_NormalizesValues.xml
new file mode 100644 (file)
index 0000000..b7f224f
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Object Name="Input">
+    <String Name="a">2</String>
+  </Object>
+  <Object Name="Output">
+    <Int Name="a">2</Int>
+  </Object>
+</ReferenceData>
diff --git a/src/gromacs/options/tests/refdata/TreeValueSupportAdjustTest_OrdersValues.xml b/src/gromacs/options/tests/refdata/TreeValueSupportAdjustTest_OrdersValues.xml
new file mode 100644 (file)
index 0000000..df43113
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Object Name="Input">
+    <Int Name="a">1</Int>
+    <Int Name="c">1</Int>
+    <Int Name="b">1</Int>
+  </Object>
+  <Object Name="Output">
+    <Int Name="b">1</Int>
+    <Int Name="a">1</Int>
+    <Int Name="c">1</Int>
+  </Object>
+</ReferenceData>
diff --git a/src/gromacs/options/tests/repeatingsection.cpp b/src/gromacs/options/tests/repeatingsection.cpp
new file mode 100644 (file)
index 0000000..faf16c2
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Tests functionality related to repeating sections.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_options
+ */
+#include "gmxpre.h"
+
+#include "gromacs/options/repeatingsection.h"
+
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/options.h"
+#include "gromacs/options/optionsassigner.h"
+
+#include "testutils/testasserts.h"
+
+namespace
+{
+
+using gmx::RepeatingOptionSection;
+
+struct SectionData
+{
+    int value;
+};
+
+TEST(RepeatingOptionSectionTest, HandlesNoInstance)
+{
+    std::vector<SectionData> values;
+    gmx::Options             options;
+    auto                     sec = options.addSection(
+                RepeatingOptionSection<SectionData>("section")
+                    .storeVector(&values));
+    using gmx::IntegerOption;
+    ASSERT_NO_THROW_GMX(sec.addOption(IntegerOption("p").store(&sec.bind().value)));
+
+    gmx::OptionsAssigner assigner(&options);
+    EXPECT_NO_THROW_GMX(assigner.start());
+    EXPECT_NO_THROW_GMX(assigner.finish());
+    EXPECT_NO_THROW_GMX(options.finish());
+
+    EXPECT_EQ(0U, values.size());
+}
+
+TEST(RepeatingOptionSectionTest, HandlesNoInstanceWithRequiredOption)
+{
+    std::vector<SectionData> values;
+    gmx::Options             options;
+    auto                     sec = options.addSection(
+                RepeatingOptionSection<SectionData>("section")
+                    .storeVector(&values));
+    using gmx::IntegerOption;
+    ASSERT_NO_THROW_GMX(sec.addOption(IntegerOption("p").store(&sec.bind().value)
+                                          .required()));
+
+    gmx::OptionsAssigner assigner(&options);
+    EXPECT_NO_THROW_GMX(assigner.start());
+    EXPECT_NO_THROW_GMX(assigner.finish());
+    EXPECT_NO_THROW_GMX(options.finish());
+
+    EXPECT_EQ(0U, values.size());
+}
+
+TEST(RepeatingOptionSectionTest, HandlesSingleInstance)
+{
+    std::vector<SectionData> values;
+    gmx::Options             options;
+    auto                     sec = options.addSection(
+                RepeatingOptionSection<SectionData>("section")
+                    .storeVector(&values));
+    using gmx::IntegerOption;
+    ASSERT_NO_THROW_GMX(sec.addOption(IntegerOption("p").store(&sec.bind().value)));
+
+    gmx::OptionsAssigner assigner(&options);
+    EXPECT_NO_THROW_GMX(assigner.start());
+    ASSERT_NO_THROW_GMX(assigner.startSection("section"));
+    ASSERT_NO_THROW_GMX(assigner.startOption("p"));
+    EXPECT_NO_THROW_GMX(assigner.appendValue("4"));
+    EXPECT_NO_THROW_GMX(assigner.finishOption());
+    EXPECT_NO_THROW_GMX(assigner.finishSection());
+    EXPECT_NO_THROW_GMX(assigner.finish());
+    EXPECT_NO_THROW_GMX(options.finish());
+
+    ASSERT_EQ(1U, values.size());
+    EXPECT_EQ(4, values[0].value);
+}
+
+TEST(RepeatingOptionSectionTest, HandlesDefaultValue)
+{
+    std::vector<SectionData> values;
+    gmx::Options             options;
+    auto                     sec = options.addSection(
+                RepeatingOptionSection<SectionData>("section")
+                    .storeVector(&values));
+    using gmx::IntegerOption;
+    ASSERT_NO_THROW_GMX(sec.addOption(IntegerOption("p").store(&sec.bind().value)
+                                          .defaultValue(3)));
+
+    gmx::OptionsAssigner assigner(&options);
+    EXPECT_NO_THROW_GMX(assigner.start());
+    ASSERT_NO_THROW_GMX(assigner.startSection("section"));
+    EXPECT_NO_THROW_GMX(assigner.finishSection());
+    EXPECT_NO_THROW_GMX(assigner.finish());
+    EXPECT_NO_THROW_GMX(options.finish());
+
+    ASSERT_EQ(1U, values.size());
+    EXPECT_EQ(3, values[0].value);
+}
+
+TEST(RepeatingOptionSectionTest, HandlesTwoInstances)
+{
+    std::vector<SectionData> values;
+    gmx::Options             options;
+    auto                     sec = options.addSection(
+                RepeatingOptionSection<SectionData>("section")
+                    .storeVector(&values));
+    using gmx::IntegerOption;
+    ASSERT_NO_THROW_GMX(sec.addOption(IntegerOption("p").store(&sec.bind().value)));
+
+    gmx::OptionsAssigner assigner(&options);
+    EXPECT_NO_THROW_GMX(assigner.start());
+    ASSERT_NO_THROW_GMX(assigner.startSection("section"));
+    ASSERT_NO_THROW_GMX(assigner.startOption("p"));
+    EXPECT_NO_THROW_GMX(assigner.appendValue("4"));
+    EXPECT_NO_THROW_GMX(assigner.finishOption());
+    EXPECT_NO_THROW_GMX(assigner.finishSection());
+    ASSERT_NO_THROW_GMX(assigner.startSection("section"));
+    ASSERT_NO_THROW_GMX(assigner.startOption("p"));
+    EXPECT_NO_THROW_GMX(assigner.appendValue("5"));
+    EXPECT_NO_THROW_GMX(assigner.finishOption());
+    EXPECT_NO_THROW_GMX(assigner.finishSection());
+    EXPECT_NO_THROW_GMX(assigner.finish());
+    EXPECT_NO_THROW_GMX(options.finish());
+
+    ASSERT_EQ(2U, values.size());
+    EXPECT_EQ(4, values[0].value);
+    EXPECT_EQ(5, values[1].value);
+}
+
+TEST(RepeatingOptionSectionTest, HandlesUnsetOptionWithImplicitDefault)
+{
+    std::vector<SectionData> values;
+    gmx::Options             options;
+    auto                     sec = options.addSection(
+                RepeatingOptionSection<SectionData>("section")
+                    .storeVector(&values));
+    using gmx::IntegerOption;
+    ASSERT_NO_THROW_GMX(sec.addOption(IntegerOption("p").store(&sec.bind().value)));
+
+    gmx::OptionsAssigner assigner(&options);
+    EXPECT_NO_THROW_GMX(assigner.start());
+    ASSERT_NO_THROW_GMX(assigner.startSection("section"));
+    ASSERT_NO_THROW_GMX(assigner.startOption("p"));
+    EXPECT_NO_THROW_GMX(assigner.appendValue("4"));
+    EXPECT_NO_THROW_GMX(assigner.finishOption());
+    EXPECT_NO_THROW_GMX(assigner.finishSection());
+    ASSERT_NO_THROW_GMX(assigner.startSection("section"));
+    EXPECT_NO_THROW_GMX(assigner.finishSection());
+    EXPECT_NO_THROW_GMX(assigner.finish());
+    EXPECT_NO_THROW_GMX(options.finish());
+
+    ASSERT_EQ(2U, values.size());
+    EXPECT_EQ(4, values[0].value);
+    EXPECT_EQ(0, values[1].value);
+}
+
+TEST(RepeatingOptionSectionTest, HandlesUnsetOptionWithExplicitDefault)
+{
+    std::vector<SectionData> values;
+    gmx::Options             options;
+    auto                     sec = options.addSection(
+                RepeatingOptionSection<SectionData>("section")
+                    .storeVector(&values));
+    using gmx::IntegerOption;
+    ASSERT_NO_THROW_GMX(sec.addOption(IntegerOption("p").store(&sec.bind().value)
+                                          .defaultValue(1)));
+
+    gmx::OptionsAssigner assigner(&options);
+    EXPECT_NO_THROW_GMX(assigner.start());
+    ASSERT_NO_THROW_GMX(assigner.startSection("section"));
+    ASSERT_NO_THROW_GMX(assigner.startOption("p"));
+    EXPECT_NO_THROW_GMX(assigner.appendValue("4"));
+    EXPECT_NO_THROW_GMX(assigner.finishOption());
+    EXPECT_NO_THROW_GMX(assigner.finishSection());
+    ASSERT_NO_THROW_GMX(assigner.startSection("section"));
+    EXPECT_NO_THROW_GMX(assigner.finishSection());
+    EXPECT_NO_THROW_GMX(assigner.finish());
+    EXPECT_NO_THROW_GMX(options.finish());
+
+    ASSERT_EQ(2U, values.size());
+    EXPECT_EQ(4, values[0].value);
+    EXPECT_EQ(1, values[1].value);
+}
+
+struct NestedSectionData
+{
+    int                      value;
+    std::vector<SectionData> subsec;
+};
+
+TEST(RepeatingOptionSectionTest, HandlesNestedSections)
+{
+    std::vector<NestedSectionData> values;
+    gmx::Options                   options;
+    auto                           sec = options.addSection(
+                RepeatingOptionSection<NestedSectionData>("section")
+                    .storeVector(&values));
+    auto                           subsec = sec.addSection(
+                RepeatingOptionSection<SectionData>("subsec")
+                    .storeVector(&sec.bind().subsec));
+    using gmx::IntegerOption;
+    ASSERT_NO_THROW_GMX(sec.addOption(IntegerOption("p").store(&sec.bind().value)));
+    ASSERT_NO_THROW_GMX(subsec.addOption(IntegerOption("p").store(&subsec.bind().value)));
+
+    gmx::OptionsAssigner assigner(&options);
+    EXPECT_NO_THROW_GMX(assigner.start());
+    ASSERT_NO_THROW_GMX(assigner.startSection("section"));
+    ASSERT_NO_THROW_GMX(assigner.startOption("p"));
+    EXPECT_NO_THROW_GMX(assigner.appendValue("4"));
+    EXPECT_NO_THROW_GMX(assigner.finishOption());
+    ASSERT_NO_THROW_GMX(assigner.startSection("subsec"));
+    ASSERT_NO_THROW_GMX(assigner.startOption("p"));
+    EXPECT_NO_THROW_GMX(assigner.appendValue("5"));
+    EXPECT_NO_THROW_GMX(assigner.finishOption());
+    EXPECT_NO_THROW_GMX(assigner.finishSection());
+    EXPECT_NO_THROW_GMX(assigner.finishSection());
+    EXPECT_NO_THROW_GMX(assigner.finish());
+    EXPECT_NO_THROW_GMX(options.finish());
+
+    ASSERT_EQ(1U, values.size());
+    EXPECT_EQ(4, values[0].value);
+    ASSERT_EQ(1U, values[0].subsec.size());
+    EXPECT_EQ(5, values[0].subsec[0].value);
+}
+
+} // namespace
index a66206b2e7e11b47566cadac06e327be5fe3fbb1..044f81ee7fc80f33aed12ce937f1f747cafb01f9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -72,7 +72,7 @@ TEST(TimeUnitBehaviorTest, ScalesAssignedOptionValue)
 {
     gmx::TimeUnitBehavior  behavior;
 
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     double                 value = 0.0;
     using gmx::DoubleOption;
     ASSERT_NO_THROW_GMX(options.addOption(DoubleOption("p").store(&value).timeValue()));
@@ -108,7 +108,7 @@ TEST(TimeUnitBehaviorTest, DoesNotScaleDefaultValues)
 {
     gmx::TimeUnitBehavior behavior;
 
-    gmx::Options          options(NULL, NULL);
+    gmx::Options          options;
     double                value = 1.5, value2 = 0.0;
     using gmx::DoubleOption;
     ASSERT_NO_THROW_GMX(options.addOption(DoubleOption("p").store(&value).timeValue()));
@@ -133,7 +133,7 @@ TEST(TimeUnitBehaviorTest, ScalesUserInputWithMultipleSources)
 {
     gmx::TimeUnitBehavior behavior;
 
-    gmx::Options          options(NULL, NULL);
+    gmx::Options          options;
     double                value = 0.0;
     using gmx::DoubleOption;
     ASSERT_NO_THROW_GMX(options.addOption(DoubleOption("p").store(&value).timeValue()));
@@ -159,7 +159,7 @@ TEST(TimeUnitBehaviorTest, TimeUnitOptionWorks)
 {
     gmx::TimeUnitBehavior behavior;
 
-    gmx::Options          options(NULL, NULL);
+    gmx::Options          options;
     double                value = 0.0;
     using gmx::DoubleOption;
     ASSERT_NO_THROW_GMX(options.addOption(DoubleOption("p").store(&value).timeValue()));
diff --git a/src/gromacs/options/tests/treesupport.cpp b/src/gromacs/options/tests/treesupport.cpp
new file mode 100644 (file)
index 0000000..cf14707
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Tests option support for operations on KeyValueTree.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_options
+ */
+#include "gmxpre.h"
+
+#include "gromacs/options/treesupport.h"
+
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/options.h"
+#include "gromacs/options/optionsection.h"
+#include "gromacs/options/repeatingsection.h"
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/keyvaluetree.h"
+#include "gromacs/utility/keyvaluetreebuilder.h"
+
+#include "testutils/refdata.h"
+#include "testutils/testasserts.h"
+
+namespace
+{
+
+/********************************************************************
+ * Tests for assignOptionsFromKeyValueTree()
+ */
+
+TEST(TreeValueSupportAssignTest, AssignsFromTree)
+{
+    int                      a0 = 0, a1 = 0;
+    std::string              b1;
+
+    gmx::Options             options;
+    options.addOption(gmx::IntegerOption("a").store(&a0));
+    auto                     sec = options.addSection(gmx::OptionSection("s"));
+    sec.addOption(gmx::IntegerOption("a").store(&a1));
+    sec.addOption(gmx::StringOption("b").store(&b1));
+
+    gmx::KeyValueTreeBuilder builder;
+    builder.rootObject().addValue<int>("a", 2);
+    auto                     obj = builder.rootObject().addObject("s");
+    obj.addValue<int>("a", 1);
+    obj.addValue<std::string>("b", "foo");
+    gmx::KeyValueTreeObject  tree = builder.build();
+
+    ASSERT_NO_THROW_GMX(gmx::assignOptionsFromKeyValueTree(&options, tree, nullptr));
+    EXPECT_NO_THROW_GMX(options.finish());
+
+    EXPECT_EQ(2, a0);
+    EXPECT_EQ(1, a1);
+    EXPECT_EQ("foo", b1);
+}
+
+struct SectionData
+{
+    int a;
+};
+
+TEST(TreeValueSupportAssignTest, AssignsFromTreeWithArrays)
+{
+    std::vector<int>         a0;
+    std::vector<SectionData> s;
+
+    gmx::Options             options;
+    options.addOption(gmx::IntegerOption("a").storeVector(&a0).multiValue());
+    auto                     sec = options.addSection(gmx::RepeatingOptionSection<SectionData>("s").storeVector(&s));
+    sec.addOption(gmx::IntegerOption("a").store(&sec.bind().a));
+
+    gmx::KeyValueTreeBuilder builder;
+    auto                     array = builder.rootObject().addUniformArray<int>("a");
+    array.addValue(1);
+    array.addValue(2);
+    auto                     objArray = builder.rootObject().addObjectArray("s");
+    auto                     obj1     = objArray.addObject();
+    obj1.addValue<int>("a", 3);
+    auto                     obj2 = objArray.addObject();
+    obj2.addValue<int>("a", 4);
+    gmx::KeyValueTreeObject  tree = builder.build();
+
+    ASSERT_NO_THROW_GMX(gmx::assignOptionsFromKeyValueTree(&options, tree, nullptr));
+    EXPECT_NO_THROW_GMX(options.finish());
+
+    ASSERT_EQ(2U, a0.size());
+    EXPECT_EQ(1, a0[0]);
+    EXPECT_EQ(2, a0[1]);
+    ASSERT_EQ(2U, s.size());
+    EXPECT_EQ(3, s[0].a);
+    EXPECT_EQ(4, s[1].a);
+}
+
+TEST(TreeValueSupportAssignErrorTest, HandlesInvalidValue)
+{
+    int                      a1 = 0;
+
+    gmx::Options             options;
+    auto                     sec = options.addSection(gmx::OptionSection("s"));
+    sec.addOption(gmx::IntegerOption("a").store(&a1));
+
+    gmx::KeyValueTreeBuilder builder;
+    auto                     obj = builder.rootObject().addObject("s");
+    obj.addValue<std::string>("a", "foo");
+    gmx::KeyValueTreeObject  tree = builder.build();
+
+    EXPECT_THROW_GMX(gmx::assignOptionsFromKeyValueTree(&options, tree, nullptr),
+                     gmx::InvalidInputError);
+}
+
+/********************************************************************
+ * Tests for adjustKeyValueTreeFromOptions()
+ */
+
+class TreeValueSupportAdjustTest : public ::testing::Test
+{
+    public:
+        void runTest()
+        {
+            gmx::test::TestReferenceData    refdata;
+            gmx::test::TestReferenceChecker checker(refdata.rootChecker());
+            gmx::KeyValueTreeObject         tree(builder_.build());
+            checker.checkKeyValueTreeObject(tree, "Input");
+            ASSERT_NO_THROW_GMX(tree = gmx::adjustKeyValueTreeFromOptions(tree, options_));
+            checker.checkKeyValueTreeObject(tree, "Output");
+        }
+
+        gmx::Options              options_;
+        gmx::KeyValueTreeBuilder  builder_;
+};
+
+TEST_F(TreeValueSupportAdjustTest, FillsDefaultValues)
+{
+    options_.addOption(gmx::IntegerOption("a").defaultValue(2));
+    runTest();
+}
+
+TEST_F(TreeValueSupportAdjustTest, FillsDefaultVectorValues)
+{
+    int v[3] = {1, 2, 3};
+    options_.addOption(gmx::IntegerOption("a").store(v).vector());
+    runTest();
+}
+
+TEST_F(TreeValueSupportAdjustTest, FillsDefaultObjectValues)
+{
+    auto sec1 = options_.addSection(gmx::OptionSection("s"));
+    sec1.addOption(gmx::IntegerOption("a").defaultValue(1));
+    auto sec2 = options_.addSection(gmx::OptionSection("r"));
+    sec2.addOption(gmx::IntegerOption("a").defaultValue(2));
+    options_.addOption(gmx::IntegerOption("a").defaultValue(3));
+    runTest();
+}
+
+TEST_F(TreeValueSupportAdjustTest, NormalizesValues)
+{
+    options_.addOption(gmx::IntegerOption("a"));
+    builder_.rootObject().addValue<std::string>("a", "2");
+    runTest();
+}
+
+TEST_F(TreeValueSupportAdjustTest, MergesDefaultValues)
+{
+    builder_.rootObject().addValue<int>("b", 1);
+    options_.addOption(gmx::IntegerOption("a").defaultValue(2));
+    options_.addOption(gmx::IntegerOption("b").defaultValue(3));
+    runTest();
+}
+
+TEST_F(TreeValueSupportAdjustTest, OrdersValues)
+{
+    builder_.rootObject().addValue<int>("a", 1);
+    builder_.rootObject().addValue<int>("c", 1);
+    builder_.rootObject().addValue<int>("b", 1);
+    options_.addOption(gmx::IntegerOption("b").defaultValue(2));
+    options_.addOption(gmx::IntegerOption("a").defaultValue(1));
+    options_.addOption(gmx::IntegerOption("c").defaultValue(3));
+    // TODO: This does not actually test the correct ordering, since the
+    // reference data is not currently order-sensitive, but the order can be
+    // checked manually from the reference data.
+    runTest();
+}
+
+} // namespace
index 73f8fc329b081311b76b770a174fb6dbee5ce157..8136f80681eabfcdd88fda6916b7e4071f96b654 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -190,10 +190,10 @@ class TimeOptionScaler : public OptionsModifyingTypeVisitor<FloatingPointOptionI
         //! Initializes a scaler with the given factor.
         explicit TimeOptionScaler(double factor) : factor_(factor) {}
 
-        void visitSubSection(Options *section)
+        void visitSection(OptionSectionInfo *section)
         {
             OptionsModifyingIterator iterator(section);
-            iterator.acceptSubSections(this);
+            iterator.acceptSections(this);
             iterator.acceptOptions(this);
         }
 
@@ -214,8 +214,8 @@ class TimeOptionScaler : public OptionsModifyingTypeVisitor<FloatingPointOptionI
 void TimeUnitBehavior::optionsFinishing(Options *options)
 {
     double factor = TimeUnitManager(timeUnit()).timeScaleFactor();
-    TimeOptionScaler<DoubleOptionInfo>(factor).visitSubSection(options);
-    TimeOptionScaler<FloatOptionInfo>(factor).visitSubSection(options);
+    TimeOptionScaler<DoubleOptionInfo>(factor).visitSection(&options->rootSection());
+    TimeOptionScaler<FloatOptionInfo>(factor).visitSection(&options->rootSection());
     if (timeUnitStore_ != NULL)
     {
         *timeUnitStore_ = static_cast<TimeUnit>(timeUnit_);
diff --git a/src/gromacs/options/treesupport.cpp b/src/gromacs/options/treesupport.cpp
new file mode 100644 (file)
index 0000000..2a45831
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Implements functions from treesupport.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_options
+ */
+#include "gmxpre.h"
+
+#include "treesupport.h"
+
+#include "gromacs/options/options.h"
+#include "gromacs/options/optionsassigner.h"
+#include "gromacs/options/optionsection.h"
+#include "gromacs/options/optionsvisitor.h"
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/ikeyvaluetreeerror.h"
+#include "gromacs/utility/keyvaluetree.h"
+#include "gromacs/utility/keyvaluetreebuilder.h"
+
+namespace gmx
+{
+
+namespace
+{
+
+class TreeAssignHelper
+{
+    public:
+        TreeAssignHelper(Options *options, IKeyValueTreeErrorHandler *errorHandler)
+            : assigner_(options), errorHandler_(errorHandler)
+        {
+            if (errorHandler_ == nullptr)
+            {
+                errorHandler_ = defaultKeyValueTreeErrorHandler();
+            }
+        }
+
+        void assignAll(const KeyValueTreeObject &root)
+        {
+            assigner_.start();
+            assignSubTree(root);
+            assigner_.finish();
+        }
+
+    private:
+        void assignSubTree(const KeyValueTreeObject &tree)
+        {
+            // TODO: Use the error handler also in other case.
+            for (const KeyValueTreeProperty &prop : tree.properties())
+            {
+                context_.append(prop.key());
+                if (prop.value().isArray())
+                {
+                    assignArray(prop.key(), prop.value().asArray());
+                }
+                else if (prop.value().isObject())
+                {
+                    assigner_.startSection(prop.key().c_str());
+                    assignSubTree(prop.value().asObject());
+                    assigner_.finishSection();
+                }
+                else
+                {
+                    assigner_.startOption(prop.key().c_str());
+                    try
+                    {
+                        assigner_.appendValue(prop.value().asVariant());
+                    }
+                    catch (UserInputError &ex)
+                    {
+                        if (!errorHandler_->onError(&ex, context_))
+                        {
+                            throw;
+                        }
+                    }
+                    assigner_.finishOption();
+                }
+                context_.pop_back();
+            }
+        }
+
+        void assignArray(const std::string       &key,
+                         const KeyValueTreeArray &array)
+        {
+            if (array.isObjectArray())
+            {
+                for (const KeyValueTreeValue &value : array.values())
+                {
+                    assigner_.startSection(key.c_str());
+                    assignSubTree(value.asObject());
+                    assigner_.finishSection();
+                }
+            }
+            else
+            {
+                assigner_.startOption(key.c_str());
+                for (const KeyValueTreeValue &value : array.values())
+                {
+                    assigner_.appendValue(value.asVariant());
+                }
+                assigner_.finishOption();
+            }
+        }
+
+        OptionsAssigner            assigner_;
+        IKeyValueTreeErrorHandler *errorHandler_;
+        KeyValueTreePath           context_;
+};
+
+class TreeIterationHelper : private OptionsVisitor
+{
+    public:
+        TreeIterationHelper(const KeyValueTreeObject &root,
+                            KeyValueTreeBuilder      *builder)
+            : currentSourceObject_(&root),
+              currentObjectBuilder_(builder->rootObject())
+        {
+        }
+
+        void processOptionSection(const OptionSectionInfo &section)
+        {
+            OptionsIterator iterator(section);
+            iterator.acceptOptions(this);
+            iterator.acceptSections(this);
+        }
+
+    private:
+        virtual void visitSection(const OptionSectionInfo &section)
+        {
+            const std::string &name          = section.name();
+            auto               parentBuilder = currentObjectBuilder_;
+            auto               parentObject  = currentSourceObject_;
+            currentObjectBuilder_ = currentObjectBuilder_.addObject(name);
+            currentSourceObject_  =
+                (currentSourceObject_ != nullptr && currentSourceObject_->keyExists(name)
+                 ? &(*currentSourceObject_)[name].asObject()
+                 : nullptr);
+            processOptionSection(section);
+            currentSourceObject_  = parentObject;
+            currentObjectBuilder_ = parentBuilder;
+        }
+        virtual void visitOption(const OptionInfo &option)
+        {
+            const std::string &name = option.name();
+            if (currentSourceObject_ == nullptr || !currentSourceObject_->keyExists(name))
+            {
+                std::vector<Variant> values = option.defaultValues();
+                if (values.size() == 1)
+                {
+                    currentObjectBuilder_.addRawValue(name, std::move(values[0]));
+                }
+                else if (values.size() > 1)
+                {
+                    auto arrayBuilder = currentObjectBuilder_.addArray(name);
+                    for (Variant &value : values)
+                    {
+                        arrayBuilder.addRawValue(std::move(value));
+                    }
+                }
+            }
+            else
+            {
+                const KeyValueTreeValue &value = (*currentSourceObject_)[name];
+                GMX_RELEASE_ASSERT(!value.isObject(), "Value objects not supported in this context");
+                std::vector<Variant>     values;
+                if (value.isArray())
+                {
+                    for (const auto &arrayValue : value.asArray().values())
+                    {
+                        GMX_RELEASE_ASSERT(!value.isObject() && !value.isArray(),
+                                           "Complex values not supported in this context");
+                        values.push_back(arrayValue.asVariant());
+                    }
+                }
+                else
+                {
+                    values.push_back(value.asVariant());
+                }
+                values = option.normalizeValues(values);
+                if (values.empty())
+                {
+                }
+                else if (values.size() == 1)
+                {
+                    currentObjectBuilder_.addRawValue(name, std::move(values[0]));
+                }
+                else
+                {
+                    auto array = currentObjectBuilder_.addArray(name);
+                    for (auto &arrayValue : values)
+                    {
+                        array.addRawValue(std::move(arrayValue));
+                    }
+                }
+            }
+        }
+
+        const KeyValueTreeObject  *currentSourceObject_;
+        KeyValueTreeObjectBuilder  currentObjectBuilder_;
+};
+
+}   // namespace
+
+//! \cond libapi
+
+void assignOptionsFromKeyValueTree(Options                   *options,
+                                   const KeyValueTreeObject  &tree,
+                                   IKeyValueTreeErrorHandler *errorHandler)
+{
+    TreeAssignHelper helper(options, errorHandler);
+    helper.assignAll(tree);
+}
+
+KeyValueTreeObject
+adjustKeyValueTreeFromOptions(const KeyValueTreeObject &tree,
+                              const Options            &options)
+{
+    KeyValueTreeBuilder builder;
+    TreeIterationHelper helper(tree, &builder);
+    helper.processOptionSection(options.rootSection());
+    return builder.build();
+}
+
+//! \endcond
+
+} // namespace gmx
diff --git a/src/gromacs/options/treesupport.h b/src/gromacs/options/treesupport.h
new file mode 100644 (file)
index 0000000..8fc4322
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares functions for using keyvaluetree.h with Options.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_TREESUPPORT_H
+#define GMX_OPTIONS_TREESUPPORT_H
+
+namespace gmx
+{
+
+class IKeyValueTreeErrorHandler;
+class KeyValueTreeObject;
+class Options;
+
+//! \cond libapi
+
+/*! \libinternal \brief
+ * Assigns option values from a given KeyValueTreeObject.
+ *
+ * Each property with a simple value (or an array of simple values) is assigned
+ * to an option with the same name.  Objects and arrays of objects are assigned
+ * to sections with the same name.
+ *
+ * \ingroup module_options
+ */
+void assignOptionsFromKeyValueTree(Options                   *options,
+                                   const KeyValueTreeObject  &tree,
+                                   IKeyValueTreeErrorHandler *errorHandler);
+/*! \libinternal \brief
+ * Adjusts a KeyValueTreeObject to the structure of given Options.
+ *
+ * Assumes that all values in the input KeyValueTreeObject are valid values for
+ * the options.  The output has all the values in the input, but in the order
+ * they are in the options.  Values are also converted to the native type for
+ * the underlying option (e.g., strings are parsed to integers if the option
+ * accepts those).  For any option that does not have a corresponding value in
+ * the input, the output has it with a default value (if one exists for the
+ * option).
+ *
+ * Does not currently work for option sections in an array.
+ *
+ * \ingroup module_options
+ */
+KeyValueTreeObject
+adjustKeyValueTreeFromOptions(const KeyValueTreeObject &tree,
+                              const Options            &options);
+
+//! \endcond
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/options/valueconverter.h b/src/gromacs/options/valueconverter.h
new file mode 100644 (file)
index 0000000..0374890
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Provides gmx::OptionValueConverterSimple.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_VALUECONVERTER_H
+#define GMX_OPTIONS_VALUECONVERTER_H
+
+#include <functional>
+#include <map>
+#include <typeindex>
+
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/variant.h"
+
+namespace gmx
+{
+
+/*! \libinternal \brief
+ * Helper for converting from Variant to a given type.
+ *
+ * \tparam OutType  Type this converter converts to.
+ *
+ * Default-constructed converter only supports identity mapping from the a
+ * Variant holding `OutType`.  To add support for additional input types,
+ * provide conversion functions with addConverter().  To use a non-identity
+ * mapping for an `OutType` -> `OutType` conversion, provide an alternative
+ * conversion from `OutType` with addConverter().
+ *
+ * \inlibraryapi
+ * \ingroup module_options
+ */
+template <typename OutType>
+class OptionValueConverterSimple
+{
+    public:
+        /*! \brief
+         * Converts a Variant value to the output type.
+         *
+         * \returns  Converted value.
+         * \throws InvalidInputError If the input Variant has a type that is
+         *     not recognized by any conversion.
+         */
+        OutType convert(const Variant &value) const
+        {
+            std::type_index type(value.type());
+            auto            iter = converters_.find(type);
+            if (iter == converters_.end())
+            {
+                if (value.isType<OutType>())
+                {
+                    return value.cast<OutType>();
+                }
+                GMX_THROW(InvalidInputError("Invalid type of value"));
+            }
+            return iter->second(value);
+        }
+
+        /*! \brief
+         * Adds a supported conversion.
+         *
+         * \tparam InType  Type to convert from.
+         * \param  func    Function to convert from `InType` to `OutType`.
+         */
+        template <typename InType>
+        void addConverter(std::function<OutType(const InType &)> func)
+        {
+            converters_[std::type_index(typeid(InType))] =
+                [func] (const Variant &value)
+                {
+                    return func(value.cast<InType>());
+                };
+        }
+        /*! \brief
+         * Adds a supported conversion from a type that can be directly cast.
+         *
+         * \tparam InType  Type to convert from with a simple cast.
+         */
+        template <typename InType>
+        void addCastConversion()
+        {
+            converters_[std::type_index(typeid(InType))] =
+                [] (const Variant &value)
+                {
+                    return static_cast<OutType>(value.cast<InType>());
+                };
+        }
+
+    private:
+        typedef std::function<OutType(const Variant &value)> ConversionFunction;
+
+        std::map<std::type_index, ConversionFunction> converters_;
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/options/valuestore.h b/src/gromacs/options/valuestore.h
new file mode 100644 (file)
index 0000000..d19652a
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \file
+ * \brief
+ * Declares implementations for IOptionValueStore.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_VALUESTORE_H
+#define GMX_OPTIONS_VALUESTORE_H
+
+#include <vector>
+
+#include "gromacs/options/ivaluestore.h"
+#include "gromacs/utility/arrayref.h"
+
+namespace gmx
+{
+
+template <typename T>
+class OptionValueStorePlain : public IOptionValueStore<T>
+{
+    public:
+        OptionValueStorePlain(T *store, int *storeCount, int initialCount)
+            : count_(initialCount), store_(store), storeCount_(storeCount)
+        {
+        }
+
+        virtual int valueCount() { return count_; }
+        virtual ArrayRef<T> values() { return ArrayRef<T>::fromArray(store_, count_); }
+        virtual void clear()
+        {
+            count_ = 0;
+            if (storeCount_ != nullptr)
+            {
+                *storeCount_ = count_;
+            }
+        }
+        virtual void reserve(size_t /*count*/)
+        {
+        }
+        virtual void append(const T &value)
+        {
+            store_[count_] = value;
+            ++count_;
+            if (storeCount_ != nullptr)
+            {
+                *storeCount_ = count_;
+            }
+        }
+
+    private:
+        int                          count_;
+        T                           *store_;
+        int                         *storeCount_;
+};
+
+template <typename T>
+class OptionValueStoreVector : public IOptionValueStore<T>
+{
+    public:
+        // cppcheck-suppress uninitMemberVar
+        explicit OptionValueStoreVector(std::vector<T> *store) : store_(store) {}
+
+        virtual int valueCount() { return static_cast<int>(store_->size()); }
+        virtual ArrayRef<T> values() { return *store_; }
+        virtual void clear() { store_->clear(); }
+        virtual void reserve(size_t count)
+        {
+            store_->reserve(store_->size() + count);
+        }
+        virtual void append(const T &value)
+        {
+            store_->push_back(value);
+        }
+
+    private:
+        std::vector<T> *store_;
+};
+
+// Specialization that works around std::vector<bool> specialities.
+template <>
+// cppcheck-suppress noConstructor
+class OptionValueStoreVector<bool> : public IOptionValueStore<bool>
+{
+    public:
+        explicit OptionValueStoreVector(std::vector<bool> *store) : store_(store)
+        {
+        }
+
+        virtual int valueCount() { return static_cast<int>(store_->size()); }
+        virtual ArrayRef<bool> values()
+        {
+            return ArrayRef<bool>::fromArray(reinterpret_cast<bool *>(boolStore_.data()),
+                                             boolStore_.size());
+        }
+        virtual void clear()
+        {
+            boolStore_.clear();
+            store_->clear();
+        }
+        virtual void reserve(size_t count)
+        {
+            boolStore_.reserve(boolStore_.size() + count);
+            store_->reserve(store_->size() + count);
+        }
+        virtual void append(const bool &value)
+        {
+            boolStore_.push_back({value});
+            store_->push_back(value);
+        }
+
+    private:
+        struct Bool
+        {
+            bool value;
+        };
+
+        std::vector<Bool>  boolStore_;
+        std::vector<bool> *store_;
+};
+
+/*! \internal
+ * \brief
+ * Value storage that does not store anywhere.
+ *
+ * This is needed because even though the values are not stored anywhere, the
+ * code still expects to access them later through valueCount() and values().
+ *
+ * \ingroup module_options
+ */
+template <typename T>
+class OptionValueStoreNull : public IOptionValueStore<T>
+{
+    public:
+        OptionValueStoreNull() : store_(&vector_) {}
+
+        virtual int valueCount() { return store_.valueCount(); }
+        virtual ArrayRef<T> values() { return store_.values(); }
+        virtual void clear() { store_.clear(); }
+        virtual void reserve(size_t count) { store_.reserve(count); }
+        virtual void append(const T &value) { store_.append(value); }
+
+    private:
+        std::vector<T>            vector_;
+        OptionValueStoreVector<T> store_;
+};
+
+} // namespace gmx
+
+#endif
index 7662589f6bcd548627afd61b1ca83e2f38610737..b184267a7a1b0ff99b5c9d9721872b9e14b0ddc1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -59,7 +59,8 @@
  *
  * Change box components to box[XX][XX]*box_rel to preserve the relative box shape
  */
-static void do_box_rel(t_inputrec *ir, matrix box_rel, matrix b, gmx_bool bInit)
+static void do_box_rel(const t_inputrec *ir, matrix box_rel,
+                       matrix b, gmx_bool bInit)
 {
     int d, d2;
 
@@ -88,7 +89,7 @@ static void do_box_rel(t_inputrec *ir, matrix box_rel, matrix b, gmx_bool bInit)
     }
 }
 
-void preserve_box_shape(t_inputrec *ir, matrix box_rel, matrix b)
+void preserve_box_shape(const t_inputrec *ir, matrix box_rel, matrix b)
 {
     if (inputrecPreserveShape(ir))
     {
@@ -96,7 +97,7 @@ void preserve_box_shape(t_inputrec *ir, matrix box_rel, matrix b)
     }
 }
 
-void set_box_rel(t_inputrec *ir, t_state *state)
+void set_box_rel(const t_inputrec *ir, t_state *state)
 {
     /* Make sure the box obeys the restrictions before we fix the ratios */
     correct_box(NULL, 0, state->box, NULL);
index 6d677debf3c0a82f2d24e8a7acad85449078815b..2f8ca1de112f51ad834fe1a51bb90fb69ced85f3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -54,7 +54,7 @@ struct t_state;
  * \param[in] box_rel Relative box
  * \param[out] b      The corrected box
  */
-void preserve_box_shape(t_inputrec *ir, matrix box_rel, matrix b);
+void preserve_box_shape(const t_inputrec *ir, matrix box_rel, matrix b);
 
 /*! \brief Determine the relative box components
  *
@@ -62,6 +62,6 @@ void preserve_box_shape(t_inputrec *ir, matrix box_rel, matrix b);
  * \param[in] ir       Input record
  * \param[inout] state Structure containing the box
  */
-void set_box_rel(struct t_inputrec *ir, t_state *state);
+void set_box_rel(const t_inputrec *ir, t_state *state);
 
 #endif
index e5078b821859e740a4d701a18b9030fb6a55a631..a793b2ba7a10120b0a5100d4acdcc7c1d9398f2b 100644 (file)
@@ -1234,92 +1234,6 @@ void pbc_dx_d(const t_pbc *pbc, const dvec x1, const dvec x2, dvec dx)
     }
 }
 
-//! Compute the box image corresponding to input vectors
-gmx_bool image_rect(ivec xi, ivec xj, ivec box_size, real rlong2, int *shift, real *r2)
-{
-    int     m, t;
-    int     dx, b, b_2;
-    real    dxr, rij2;
-
-    rij2 = 0.0;
-    t    = 0;
-    for (m = 0; (m < DIM); m++)
-    {
-        dx  = xi[m]-xj[m];
-        t  *= DIM;
-        b   = box_size[m];
-        b_2 = b/2;
-        if (dx < -b_2)
-        {
-            t  += 2;
-            dx += b;
-        }
-        else if (dx > b_2)
-        {
-            dx -= b;
-        }
-        else
-        {
-            t += 1;
-        }
-        dxr   = dx;
-        rij2 += dxr*dxr;
-        if (rij2 >= rlong2)
-        {
-            return FALSE;
-        }
-    }
-
-    *shift = t;
-    *r2    = rij2;
-    return TRUE;
-}
-
-gmx_bool image_cylindric(ivec xi, ivec xj, ivec box_size, real rlong2,
-                         int *shift, real *r2)
-{
-    int     m, t;
-    int     dx, b, b_2;
-    real    dxr, rij2;
-
-    rij2 = 0.0;
-    t    = 0;
-    for (m = 0; (m < DIM); m++)
-    {
-        dx  = xi[m]-xj[m];
-        t  *= DIM;
-        b   = box_size[m];
-        b_2 = b/2;
-        if (dx < -b_2)
-        {
-            t  += 2;
-            dx += b;
-        }
-        else if (dx > b_2)
-        {
-            dx -= b;
-        }
-        else
-        {
-            t += 1;
-        }
-
-        dxr   = dx;
-        rij2 += dxr*dxr;
-        if (m < ZZ)
-        {
-            if (rij2 >= rlong2)
-            {
-                return FALSE;
-            }
-        }
-    }
-
-    *shift = t;
-    *r2    = rij2;
-    return TRUE;
-}
-
 void calc_shifts(const matrix box, rvec shift_vec[])
 {
     int k, l, m, d, n, test;
index ea0148da22b331e4befe07e56197066ffd2c2c2e..c14f0215173d1ee28973fb60321ed46e854fe5ae 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2012,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2012,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -271,50 +271,6 @@ int pbc_dx_aiuc(const t_pbc *pbc, const rvec x1, const rvec x2, rvec dx);
  */
 void pbc_dx_d(const t_pbc *pbc, const dvec x1, const dvec x2, dvec dx);
 
-/*! \brief Calculate the distance between xi and xj for a rectangular box.
- *
- * It is assumed that rlong2 is scaled the same way as the ivecs xi and xj.
- * \param[in]  xi     Box index
- * \param[in]  xj     Box index
- * \param[in]  box    The box of grid cells
- * \param[in]  rlong2 Cutoff squared
- * \param[out] shift  The shift code
- * \param[out] r2     The distance (squared???)
- * \return TRUE when the distance is SMALLER than rlong2
- */
-gmx_bool image_rect(ivec xi, ivec xj, imatrix box,
-                    real rlong2, int *shift, real *r2);
-
-/*! \brief Calculate the distance between xi and xj for a triclinic box.
- *
- * It is assumed that rlong2 is scaled the same way as the ivecs xi and xj.
- * \param[in]  xi     Box index
- * \param[in]  xj     Box index
- * \param[in]  box    Matrix of box grid cells
- * \param[in]  rlong2 Cutoff squared
- * \param[out] shift  The shift code
- * \param[out] r2     The distance (squared???)
- * \return TRUE when the distance is SMALLER than rlong2
- */
-gmx_bool image_tri(const ivec xi, const ivec xj, const imatrix box,
-                   real rlong2, int *shift, real *r2);
-
-/*! \brief Compute distance vector when using cylindrical cutoff
- *
- * Calculate the distance between xi and xj for a rectangular box
- * using a cylindric cutoff for long-range only.
- * It is assumed that rlong2 is scaled the same way as the ivecs xi and xj.
- * \param[in]  xi       Box index
- * \param[in]  xj       Box index
- * \param[in]  box_size Number of box grid cells
- * \param[in]  rlong2   Cutoff squared
- * \param[out] shift    The shift code
- * \param[out] r2       The distance (squared???)
- * \return TRUE when the distance is SMALLER than rlong2 (in X and Y dir)
- */
-gmx_bool image_cylindric(const ivec xi, const ivec xj, const ivec box_size,
-                         real rlong2, int *shift, real *r2);
-
 /*! \brief Computes shift vectors
  *
  * This routine calculates ths shift vectors necessary to use the
index 0b53424b2913d38de4da0c0f3eeed0b93d7ac979..de42a26d775028330fd97d0f0f7a120433a7ef88 100644 (file)
@@ -66,7 +66,7 @@
 #include "gromacs/mdtypes/mdatom.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/pulling/pull_internal.h"
-#include "gromacs/topology/mtop_util.h"
+#include "gromacs/topology/mtop_lookup.h"
 #include "gromacs/topology/topology.h"
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/exceptions.h"
@@ -1916,13 +1916,6 @@ static void init_pull_group_index(FILE *fplog, t_commrec *cr,
                                   const gmx_mtop_t *mtop,
                                   const t_inputrec *ir, real lambda)
 {
-    int                   i, ii, d, nfrozen, ndim;
-    real                  m, w, mbd;
-    double                tmass, wmass, wwmass;
-    const gmx_groups_t   *groups;
-    gmx_mtop_atomlookup_t alook;
-    t_atom               *atom;
-
     if (EI_ENERGY_MINIMIZATION(ir->eI) || ir->eI == eiBD)
     {
         /* There are no masses in the integrator.
@@ -1957,21 +1950,20 @@ static void init_pull_group_index(FILE *fplog, t_commrec *cr,
         }
     }
 
-    groups = &mtop->groups;
-
-    alook = gmx_mtop_atomlookup_init(mtop);
+    const gmx_groups_t *groups = &mtop->groups;
 
-    nfrozen = 0;
-    tmass   = 0;
-    wmass   = 0;
-    wwmass  = 0;
-    for (i = 0; i < pg->params.nat; i++)
+    /* Count frozen dimensions and (weighted) mass */
+    int    nfrozen = 0;
+    double tmass   = 0;
+    double wmass   = 0;
+    double wwmass  = 0;
+    int    molb    = 0;
+    for (int i = 0; i < pg->params.nat; i++)
     {
-        ii = pg->params.ind[i];
-        gmx_mtop_atomnr_to_atom(alook, ii, &atom);
+        int ii = pg->params.ind[i];
         if (bConstraint && ir->opts.nFreeze)
         {
-            for (d = 0; d < DIM; d++)
+            for (int d = 0; d < DIM; d++)
             {
                 if (pulldim_con[d] == 1 &&
                     ir->opts.nFreeze[ggrpnr(groups, egcFREEZE, ii)][d])
@@ -1980,14 +1972,17 @@ static void init_pull_group_index(FILE *fplog, t_commrec *cr,
                 }
             }
         }
+        const t_atom &atom = mtopGetAtomParameters(mtop, ii, &molb);
+        real          m;
         if (ir->efep == efepNO)
         {
-            m = atom->m;
+            m = atom.m;
         }
         else
         {
-            m = (1 - lambda)*atom->m + lambda*atom->mB;
+            m = (1 - lambda)*atom.m + lambda*atom.mB;
         }
+        real w;
         if (pg->params.nweight > 0)
         {
             w = pg->params.weight[i];
@@ -2005,6 +2000,7 @@ static void init_pull_group_index(FILE *fplog, t_commrec *cr,
         }
         else if (ir->eI == eiBD)
         {
+            real mbd;
             if (ir->bd_fric)
             {
                 mbd = ir->bd_fric*ir->delta_t;
@@ -2029,8 +2025,6 @@ static void init_pull_group_index(FILE *fplog, t_commrec *cr,
         wwmass += m*w*w;
     }
 
-    gmx_mtop_atomlookup_destroy(alook);
-
     if (wmass == 0)
     {
         /* We can have single atom groups with zero mass with potential pulling
@@ -2071,8 +2065,8 @@ static void init_pull_group_index(FILE *fplog, t_commrec *cr,
     }
     else
     {
-        ndim = 0;
-        for (d = 0; d < DIM; d++)
+        int ndim = 0;
+        for (int d = 0; d < DIM; d++)
         {
             ndim += pulldim_con[d]*pg->params.nat;
         }
index a9e1bac40dedaa320789d02187251c08f1621a34..7ebe0db0fb3b65bd75ec10f57873171b35739eb7 100644 (file)
@@ -65,7 +65,7 @@
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/timing/cyclecounter.h"
 #include "gromacs/timing/wallcycle.h"
-#include "gromacs/topology/mtop_util.h"
+#include "gromacs/topology/mtop_lookup.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/pleasecite.h"
 #include "gromacs/utility/qsort_threadsafe.h"
@@ -3390,10 +3390,8 @@ static void init_rot_group(FILE *fplog, t_commrec *cr, int g, t_rotgrp *rotg,
     int                   i, ii;
     rvec                  coord, xref, *xdum;
     gmx_bool              bFlex, bColl;
-    t_atom               *atom;
     gmx_enfrotgrp_t       erg; /* Pointer to enforced rotation group data */
     int                   ref_firstindex, ref_lastindex;
-    gmx_mtop_atomlookup_t alook = NULL;
     real                  mass, totalmass;
     real                  start = 0.0;
     double                t_start;
@@ -3461,10 +3459,6 @@ static void init_rot_group(FILE *fplog, t_commrec *cr, int g, t_rotgrp *rotg,
 
     /* Copy the masses so that the center can be determined. For all types of
      * enforced rotation, we store the masses in the erg->mc array. */
-    if (rotg->bMassW)
-    {
-        alook = gmx_mtop_atomlookup_init(mtop);
-    }
     snew(erg->mc, rotg->nat);
     if (bFlex)
     {
@@ -3475,12 +3469,12 @@ static void init_rot_group(FILE *fplog, t_commrec *cr, int g, t_rotgrp *rotg,
         snew(erg->m_loc, rotg->nat);
     }
     totalmass = 0.0;
+    int molb  = 0;
     for (i = 0; i < rotg->nat; i++)
     {
         if (rotg->bMassW)
         {
-            gmx_mtop_atomnr_to_atom(alook, rotg->ind[i], &atom);
-            mass = atom->m;
+            mass = mtopGetAtomMass(mtop, rotg->ind[i], &molb);
         }
         else
         {
@@ -3491,11 +3485,6 @@ static void init_rot_group(FILE *fplog, t_commrec *cr, int g, t_rotgrp *rotg,
     }
     erg->invmass = 1.0/totalmass;
 
-    if (rotg->bMassW)
-    {
-        gmx_mtop_atomlookup_destroy(alook);
-    }
-
     /* Set xc_ref_center for any rotation potential */
     if ((rotg->eType == erotgISO) || (rotg->eType == erotgPM) || (rotg->eType == erotgRM) || (rotg->eType == erotgRM2))
     {
index bb05dd0b28291eb3ddc620459d56b295490382ba..ac850cfeb87603918218b2c91ad968dc71ab08aa 100644 (file)
@@ -96,8 +96,9 @@ namespace gmx
  *  produce errors. Even for newer compilers, libstdc++ and libc++ appear to
  *  use different algorithms to generate it, which means their values differ
  *  in contrast to the uniform and normal distributions where they are
- *  identical. To avoid both the gcc-4.6 bug and make it easier to use GROMACS
- *   unit tests that depend on random numbers we have our own implementation.
+ *  identical. To avoid both compiler bugs and make it easier to use
+ *  GROMACS unit tests that depend on random numbers, we have our
+ *  own implementation.
  *
  *  Be warned that the gamma distribution works like the standard
  *  normal distribution and keeps drawing values from the random engine
index 7be8c4ed4c2f681aa65ed49b6b38d58d9b445b43..0639890a0db148b09f437eda7c01997ed4340c81 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 #include "gromacs/math/vec.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/topology/block.h"
+#include "gromacs/topology/mtop_lookup.h"
 #include "gromacs/topology/topology.h"
 #include "gromacs/utility/gmxassert.h"
 
 void
-gmx_calc_cog(const t_topology * /* top */, rvec x[], int nrefat, const int index[], rvec xout)
+gmx_calc_cog(const gmx_mtop_t * /* top */, rvec x[], int nrefat, const int index[], rvec xout)
 {
     int                 m, ai;
 
@@ -74,20 +75,18 @@ gmx_calc_cog(const t_topology * /* top */, rvec x[], int nrefat, const int index
  * mass are calculated, and hence a topology with masses is required.
  */
 void
-gmx_calc_com(const t_topology *top, rvec x[], int nrefat, const int index[], rvec xout)
+gmx_calc_com(const gmx_mtop_t *top, rvec x[], int nrefat, const int index[], rvec xout)
 {
-    int                 m, j, ai;
-    real                mass, mtot;
-
-    GMX_RELEASE_ASSERT(top != nullptr,
+    GMX_RELEASE_ASSERT(gmx_mtop_has_masses(top),
                        "No masses available while mass weighting was requested");
     clear_rvec(xout);
-    mtot = 0;
-    for (m = 0; m < nrefat; ++m)
+    real mtot = 0;
+    int  molb = 0;
+    for (int m = 0; m < nrefat; ++m)
     {
-        ai   = index[m];
-        mass = top->atoms.atom[ai].m;
-        for (j = 0; j < DIM; ++j)
+        const int  ai   = index[m];
+        const real mass = mtopGetAtomMass(top, ai, &molb);
+        for (int j = 0; j < DIM; ++j)
         {
             xout[j] += mass * x[ai][j];
         }
@@ -104,20 +103,18 @@ gmx_calc_com(const t_topology *top, rvec x[], int nrefat, const int index[], rve
  * \param[out] fout   Force on the COG position for the indexed atoms.
  */
 void
-gmx_calc_cog_f(const t_topology *top, rvec f[], int nrefat, const int index[], rvec fout)
+gmx_calc_cog_f(const gmx_mtop_t *top, rvec f[], int nrefat, const int index[], rvec fout)
 {
-    int                 m, j, ai;
-    real                mass, mtot;
-
-    GMX_RELEASE_ASSERT(top != nullptr,
+    GMX_RELEASE_ASSERT(gmx_mtop_has_masses(top),
                        "No masses available while mass weighting was requested");
     clear_rvec(fout);
-    mtot = 0;
-    for (m = 0; m < nrefat; ++m)
+    real mtot = 0;
+    int  molb = 0;
+    for (int m = 0; m < nrefat; ++m)
     {
-        ai   = index[m];
-        mass = top->atoms.atom[ai].m;
-        for (j = 0; j < DIM; ++j)
+        const int  ai   = index[m];
+        const real mass = mtopGetAtomMass(top, ai, &molb);
+        for (int j = 0; j < DIM; ++j)
         {
             fout[j] += f[ai][j] / mass;
         }
@@ -127,7 +124,7 @@ gmx_calc_cog_f(const t_topology *top, rvec f[], int nrefat, const int index[], r
 }
 
 void
-gmx_calc_com_f(const t_topology * /* top */, rvec f[], int nrefat, const int index[], rvec fout)
+gmx_calc_com_f(const gmx_mtop_t * /* top */, rvec f[], int nrefat, const int index[], rvec fout)
 {
     clear_rvec(fout);
     for (int m = 0; m < nrefat; ++m)
@@ -151,7 +148,7 @@ gmx_calc_com_f(const t_topology * /* top */, rvec f[], int nrefat, const int ind
  * Other parameters are passed unmodified to these functions.
  */
 void
-gmx_calc_comg(const t_topology *top, rvec x[], int nrefat, const int index[],
+gmx_calc_comg(const gmx_mtop_t *top, rvec x[], int nrefat, const int index[],
               bool bMass, rvec xout)
 {
     if (bMass)
@@ -178,7 +175,7 @@ gmx_calc_comg(const t_topology *top, rvec x[], int nrefat, const int index[],
  * Other parameters are passed unmodified to these functions.
  */
 void
-gmx_calc_comg_f(const t_topology *top, rvec f[], int nrefat, const int index[],
+gmx_calc_comg_f(const gmx_mtop_t *top, rvec f[], int nrefat, const int index[],
                 bool bMass, rvec fout)
 {
     if (bMass)
@@ -203,7 +200,7 @@ gmx_calc_comg_f(const t_topology *top, rvec f[], int nrefat, const int index[],
  * Works exactly as gmx_calc_com_pbc(), but calculates the center of geometry.
  */
 void
-gmx_calc_cog_pbc(const t_topology *top, rvec x[], t_pbc *pbc,
+gmx_calc_cog_pbc(const gmx_mtop_t *top, rvec x[], const t_pbc *pbc,
                  int nrefat, const int index[], rvec xout)
 {
     const real          tol = 1e-4;
@@ -258,25 +255,20 @@ gmx_calc_cog_pbc(const t_topology *top, rvec x[], t_pbc *pbc,
  * Modified from src/tools/gmx_sorient.c in Gromacs distribution.
  */
 void
-gmx_calc_com_pbc(const t_topology *top, rvec x[], t_pbc *pbc,
+gmx_calc_com_pbc(const gmx_mtop_t *top, rvec x[], const t_pbc *pbc,
                  int nrefat, const int index[], rvec xout)
 {
-    const real          tol = 1e-4;
-    bool                bChanged;
-    int                 m, j, ai, iter;
-    real                mass, mtot;
-    rvec                dx, xtest;
-
-    GMX_RELEASE_ASSERT(top != nullptr,
+    GMX_RELEASE_ASSERT(gmx_mtop_has_masses(top),
                        "No masses available while mass weighting was requested");
     /* First simple calculation */
     clear_rvec(xout);
-    mtot = 0;
-    for (m = 0; m < nrefat; ++m)
+    real mtot = 0;
+    int  molb = 0;
+    for (int m = 0; m < nrefat; ++m)
     {
-        ai   = index[m];
-        mass = top->atoms.atom[ai].m;
-        for (j = 0; j < DIM; ++j)
+        const int  ai   = index[m];
+        const real mass = mtopGetAtomMass(top, ai, &molb);
+        for (int j = 0; j < DIM; ++j)
         {
             xout[j] += mass * x[ai][j];
         }
@@ -286,17 +278,20 @@ gmx_calc_com_pbc(const t_topology *top, rvec x[], t_pbc *pbc,
     /* Now check if any atom is more than half the box from the COM */
     if (pbc)
     {
-        iter = 0;
+        const real tol  = 1e-4;
+        bool       bChanged;
         do
         {
             bChanged = false;
-            for (m = 0; m < nrefat; ++m)
+            molb     = 0;
+            for (int m = 0; m < nrefat; ++m)
             {
-                ai   = index[m];
-                mass = top->atoms.atom[ai].m / mtot;
+                rvec       dx, xtest;
+                const int  ai   = index[m];
+                const real mass = mtopGetAtomMass(top, ai, &molb) / mtot;
                 pbc_dx(pbc, x[ai], xout, dx);
                 rvec_add(xout, dx, xtest);
-                for (j = 0; j < DIM; ++j)
+                for (int j = 0; j < DIM; ++j)
                 {
                     if (fabs(xtest[j] - x[ai][j]) > tol)
                     {
@@ -307,7 +302,6 @@ gmx_calc_com_pbc(const t_topology *top, rvec x[], t_pbc *pbc,
                     }
                 }
             }
-            iter++;
         }
         while (bChanged);
     }
@@ -328,7 +322,7 @@ gmx_calc_com_pbc(const t_topology *top, rvec x[], t_pbc *pbc,
  * Other parameters are passed unmodified to these functions.
  */
 void
-gmx_calc_comg_pbc(const t_topology *top, rvec x[], t_pbc *pbc,
+gmx_calc_comg_pbc(const gmx_mtop_t *top, rvec x[], const t_pbc *pbc,
                   int nrefat, const int index[], bool bMass, rvec xout)
 {
     if (bMass)
@@ -343,7 +337,7 @@ gmx_calc_comg_pbc(const t_topology *top, rvec x[], t_pbc *pbc,
 
 
 void
-gmx_calc_cog_block(const t_topology * /* top */, rvec x[], const t_block *block, const int index[],
+gmx_calc_cog_block(const gmx_mtop_t * /* top */, rvec x[], const t_block *block, const int index[],
                    rvec xout[])
 {
     int                 b, i, ai;
@@ -372,24 +366,22 @@ gmx_calc_cog_block(const t_topology * /* top */, rvec x[], const t_block *block,
  * mass are calculated, and hence a topology with masses is required.
  */
 void
-gmx_calc_com_block(const t_topology *top, rvec x[], const t_block *block, const int index[],
+gmx_calc_com_block(const gmx_mtop_t *top, rvec x[], const t_block *block, const int index[],
                    rvec xout[])
 {
-    int                 b, i, ai, d;
-    rvec                xb;
-    real                mass, mtot;
-
-    GMX_RELEASE_ASSERT(top != nullptr,
+    GMX_RELEASE_ASSERT(gmx_mtop_has_masses(top),
                        "No masses available while mass weighting was requested");
-    for (b = 0; b < block->nr; ++b)
+    int molb = 0;
+    for (int b = 0; b < block->nr; ++b)
     {
+        rvec xb;
         clear_rvec(xb);
-        mtot = 0;
-        for (i = block->index[b]; i < block->index[b+1]; ++i)
+        real mtot = 0;
+        for (int i = block->index[b]; i < block->index[b+1]; ++i)
         {
-            ai   = index[i];
-            mass = top->atoms.atom[ai].m;
-            for (d = 0; d < DIM; ++d)
+            const int  ai   = index[i];
+            const real mass = mtopGetAtomMass(top, ai, &molb);
+            for (int d = 0; d < DIM; ++d)
             {
                 xb[d] += mass * x[ai][d];
             }
@@ -407,24 +399,22 @@ gmx_calc_com_block(const t_topology *top, rvec x[], const t_block *block, const
  * \param[out] fout  \p block->nr Forces on COG positions.
  */
 void
-gmx_calc_cog_f_block(const t_topology *top, rvec f[], const t_block *block, const int index[],
+gmx_calc_cog_f_block(const gmx_mtop_t *top, rvec f[], const t_block *block, const int index[],
                      rvec fout[])
 {
-    int                 b, i, ai, d;
-    rvec                fb;
-    real                mass, mtot;
-
-    GMX_RELEASE_ASSERT(top != nullptr,
+    GMX_RELEASE_ASSERT(gmx_mtop_has_masses(top),
                        "No masses available while mass weighting was requested");
-    for (b = 0; b < block->nr; ++b)
+    int molb = 0;
+    for (int b = 0; b < block->nr; ++b)
     {
+        rvec fb;
         clear_rvec(fb);
-        mtot = 0;
-        for (i = block->index[b]; i < block->index[b+1]; ++i)
+        real mtot = 0;
+        for (int i = block->index[b]; i < block->index[b+1]; ++i)
         {
-            ai   = index[i];
-            mass = top->atoms.atom[ai].m;
-            for (d = 0; d < DIM; ++d)
+            const int  ai   = index[i];
+            const real mass = mtopGetAtomMass(top, ai, &molb);
+            for (int d = 0; d < DIM; ++d)
             {
                 fb[d] += f[ai][d] / mass;
             }
@@ -435,7 +425,7 @@ gmx_calc_cog_f_block(const t_topology *top, rvec f[], const t_block *block, cons
 }
 
 void
-gmx_calc_com_f_block(const t_topology * /* top */, rvec f[], const t_block *block, const int index[],
+gmx_calc_com_f_block(const gmx_mtop_t * /* top */, rvec f[], const t_block *block, const int index[],
                      rvec fout[])
 {
     for (int b = 0; b < block->nr; ++b)
@@ -465,7 +455,7 @@ gmx_calc_com_f_block(const t_topology * /* top */, rvec f[], const t_block *bloc
  * Other parameters are passed unmodified to these functions.
  */
 void
-gmx_calc_comg_block(const t_topology *top, rvec x[], const t_block *block, const int index[],
+gmx_calc_comg_block(const gmx_mtop_t *top, rvec x[], const t_block *block, const int index[],
                     bool bMass, rvec xout[])
 {
     if (bMass)
@@ -492,7 +482,7 @@ gmx_calc_comg_block(const t_topology *top, rvec x[], const t_block *block, const
  * Other parameters are passed unmodified to these functions.
  */
 void
-gmx_calc_comg_f_block(const t_topology *top, rvec f[], const t_block *block, const int index[],
+gmx_calc_comg_f_block(const gmx_mtop_t *top, rvec f[], const t_block *block, const int index[],
                       bool bMass, rvec fout[])
 {
     if (bMass)
@@ -524,11 +514,11 @@ gmx_calc_comg_f_block(const t_topology *top, rvec f[], const t_block *block, con
  * crashes.
  */
 void
-gmx_calc_comg_blocka(const t_topology *top, rvec x[], const t_blocka *block,
+gmx_calc_comg_blocka(const gmx_mtop_t *top, rvec x[], const t_blocka *block,
                      bool bMass, rvec xout[])
 {
     /* TODO: It would probably be better to do this without the type cast */
-    gmx_calc_comg_block(top, x, (t_block *)block, block->a, bMass, xout);
+    gmx_calc_comg_block(top, x, reinterpret_cast<const t_block *>(block), block->a, bMass, xout);
 }
 
 /*!
@@ -550,9 +540,9 @@ gmx_calc_comg_blocka(const t_topology *top, rvec x[], const t_blocka *block,
  * crashes.
  */
 void
-gmx_calc_comg_f_blocka(const t_topology *top, rvec f[], const t_blocka *block,
+gmx_calc_comg_f_blocka(const gmx_mtop_t *top, rvec f[], const t_blocka *block,
                        bool bMass, rvec fout[])
 {
     /* TODO: It would probably be better to do this without the type cast */
-    gmx_calc_comg_f_block(top, f, (t_block *)block, block->a, bMass, fout);
+    gmx_calc_comg_f_block(top, f, reinterpret_cast<const t_block *>(block), block->a, bMass, fout);
 }
index 21058cf7910765b1bb73db3618e04226178d3ae2..12b92b4b92ba6d2efed9308af0b30e99111b2a57 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 
 #include "gromacs/math/vectypes.h"
 
+struct gmx_mtop_t;
 struct t_block;
 struct t_blocka;
 struct t_pbc;
-struct t_topology;
 
 /*! \brief
  * Calculate a single center of geometry.
@@ -91,13 +91,13 @@ struct t_topology;
  * \param[out] xout   COG position for the indexed atoms.
  */
 void
-gmx_calc_cog(const t_topology *top, rvec x[], int nrefat, const int index[], rvec xout);
+gmx_calc_cog(const gmx_mtop_t *top, rvec x[], int nrefat, const int index[], rvec xout);
 /** Calculate a single center of mass. */
 void
-gmx_calc_com(const t_topology *top, rvec x[], int nrefat, const int index[], rvec xout);
+gmx_calc_com(const gmx_mtop_t *top, rvec x[], int nrefat, const int index[], rvec xout);
 /** Calculate force on a single center of geometry. */
 void
-gmx_calc_cog_f(const t_topology *top, rvec f[], int nrefat, const int index[], rvec fout);
+gmx_calc_cog_f(const gmx_mtop_t *top, rvec f[], int nrefat, const int index[], rvec fout);
 /*! \brief
  * Calculate force on a single center of mass.
  *
@@ -108,27 +108,27 @@ gmx_calc_cog_f(const t_topology *top, rvec f[], int nrefat, const int index[], r
  * \param[out] fout   Force on the COM position for the indexed atoms.
  */
 void
-gmx_calc_com_f(const t_topology *top, rvec f[], int nrefat, const int index[], rvec fout);
+gmx_calc_com_f(const gmx_mtop_t *top, rvec f[], int nrefat, const int index[], rvec fout);
 /** Calculate a single center of mass/geometry. */
 void
-gmx_calc_comg(const t_topology *top, rvec x[], int nrefat, const int index[],
+gmx_calc_comg(const gmx_mtop_t *top, rvec x[], int nrefat, const int index[],
               bool bMass, rvec xout);
 /** Calculate force on a single center of mass/geometry. */
 void
-gmx_calc_comg_f(const t_topology *top, rvec f[], int nrefat, const int index[],
+gmx_calc_comg_f(const gmx_mtop_t *top, rvec f[], int nrefat, const int index[],
                 bool bMass, rvec fout);
 
 /** Calculate a single center of geometry iteratively, taking PBC into account. */
 void
-gmx_calc_cog_pbc(const t_topology *top, rvec x[], t_pbc *pbc,
+gmx_calc_cog_pbc(const gmx_mtop_t *top, rvec x[], const t_pbc *pbc,
                  int nrefat, const int index[], rvec xout);
 /** Calculate a single center of mass iteratively, taking PBC into account. */
 void
-gmx_calc_com_pbc(const t_topology *top, rvec x[], t_pbc *pbc,
+gmx_calc_com_pbc(const gmx_mtop_t *top, rvec x[], const t_pbc *pbc,
                  int nrefat, const int index[], rvec xout);
 /** Calculate a single center of mass/geometry iteratively with PBC. */
 void
-gmx_calc_comg_pbc(const t_topology *top, rvec x[], t_pbc *pbc,
+gmx_calc_comg_pbc(const gmx_mtop_t *top, rvec x[], const t_pbc *pbc,
                   int nrefat, const int index[], bool bMass, rvec xout);
 
 /*! \brief
@@ -141,15 +141,15 @@ gmx_calc_comg_pbc(const t_topology *top, rvec x[], t_pbc *pbc,
  * \param[out] xout  \p block->nr COG positions.
  */
 void
-gmx_calc_cog_block(const t_topology *top, rvec x[], const t_block *block,
+gmx_calc_cog_block(const gmx_mtop_t *top, rvec x[], const t_block *block,
                    const int index[], rvec xout[]);
 /** Calculate centers of mass for a blocked index. */
 void
-gmx_calc_com_block(const t_topology *top, rvec x[], const t_block *block,
+gmx_calc_com_block(const gmx_mtop_t *top, rvec x[], const t_block *block,
                    const int index[], rvec xout[]);
 /** Calculate forces on centers of geometry for a blocked index. */
 void
-gmx_calc_cog_f_block(const t_topology *top, rvec f[], const t_block *block,
+gmx_calc_cog_f_block(const gmx_mtop_t *top, rvec f[], const t_block *block,
                      const int index[], rvec fout[]);
 /*! \brief
  * Calculate forces on centers of mass for a blocked index.
@@ -161,23 +161,23 @@ gmx_calc_cog_f_block(const t_topology *top, rvec f[], const t_block *block,
  * \param[out] fout  \p block->nr Forces on COM positions.
  */
 void
-gmx_calc_com_f_block(const t_topology *top, rvec f[], const t_block *block,
+gmx_calc_com_f_block(const gmx_mtop_t *top, rvec f[], const t_block *block,
                      const int index[], rvec fout[]);
 /** Calculate centers of mass/geometry for a blocked index. */
 void
-gmx_calc_comg_block(const t_topology *top, rvec x[], const t_block *block,
+gmx_calc_comg_block(const gmx_mtop_t *top, rvec x[], const t_block *block,
                     const int index[], bool bMass, rvec xout[]);
 /** Calculate forces on centers of mass/geometry for a blocked index. */
 void
-gmx_calc_comg_f_block(const t_topology *top, rvec f[], const t_block *block,
+gmx_calc_comg_f_block(const gmx_mtop_t *top, rvec f[], const t_block *block,
                       const int index[], bool bMass, rvec fout[]);
 /** Calculate centers of mass/geometry for a set of blocks; */
 void
-gmx_calc_comg_blocka(const t_topology *top, rvec x[], const t_blocka *block,
+gmx_calc_comg_blocka(const gmx_mtop_t *top, rvec x[], const t_blocka *block,
                      bool bMass, rvec xout[]);
 /** Calculate forces on centers of mass/geometry for a set of blocks; */
 void
-gmx_calc_comg_f_blocka(const t_topology *top, rvec x[], const t_blocka *block,
+gmx_calc_comg_f_blocka(const gmx_mtop_t *top, rvec x[], const t_blocka *block,
                        bool bMass, rvec xout[]);
 
 #endif
index a5f9239677051c28425d2705f7cc301287a68311..a35ac378a01d52dfc82ff246087b6ac29bf9b53e 100644 (file)
@@ -1829,7 +1829,7 @@ store_param_val(const SelectionTreeElementPointer &sel)
  * is prevented by using \ref SEL_METHODINIT and \ref SEL_OUTINIT flags.
  */
 static void
-init_method(const SelectionTreeElementPointer &sel, t_topology *top, int isize)
+init_method(const SelectionTreeElementPointer &sel, const gmx_mtop_t *top, int isize)
 {
     /* Find out whether there are any atom-valued parameters */
     bool bAtomVal                     = false;
index e1f4df2f90be4d300eb740e54ab66ede04508446..70e5fd1ddd7cc3d9b1b89ee09f34fe6f7d499b3c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -369,7 +369,7 @@ _gmx_sel_print_evalfunc_name(FILE *fp, gmx::sel_evalfunc evalfunc)
 void
 _gmx_sel_evaluate_init(gmx_sel_evaluate_t *data,
                        gmx_sel_mempool_t *mp, gmx_ana_index_t *gall,
-                       t_topology *top, t_trxframe *fr, t_pbc *pbc)
+                       const gmx_mtop_t *top, t_trxframe *fr, t_pbc *pbc)
 {
     data->mp   = mp;
     data->gall = gall;
@@ -961,18 +961,17 @@ _gmx_sel_evaluate_method(gmx_sel_evaluate_t                     *data,
                          gmx_ana_index_t                        *g)
 {
     _gmx_sel_evaluate_method_params(data, sel, g);
+    gmx::SelMethodEvalContext context(data->top, data->fr, data->pbc);
     if (sel->flags & SEL_INITFRAME)
     {
         sel->flags &= ~SEL_INITFRAME;
-        sel->u.expr.method->init_frame(data->top, data->fr, data->pbc,
-                                       sel->u.expr.mdata);
+        sel->u.expr.method->init_frame(context, sel->u.expr.mdata);
     }
     if (sel->u.expr.pc)
     {
         gmx_ana_poscalc_update(sel->u.expr.pc, sel->u.expr.pos, g,
                                data->fr, data->pbc);
-        sel->u.expr.method->pupdate(data->top, data->fr, data->pbc,
-                                    sel->u.expr.pos, &sel->v,
+        sel->u.expr.method->pupdate(context, sel->u.expr.pos, &sel->v,
                                     sel->u.expr.mdata);
         if ((sel->flags & SEL_ATOMVAL) && sel->v.nr < g->isize)
         {
@@ -989,8 +988,7 @@ _gmx_sel_evaluate_method(gmx_sel_evaluate_t                     *data,
     }
     else
     {
-        sel->u.expr.method->update(data->top, data->fr, data->pbc, g,
-                                   &sel->v, sel->u.expr.mdata);
+        sel->u.expr.method->update(context, g, &sel->v, sel->u.expr.mdata);
     }
 }
 
@@ -1015,18 +1013,17 @@ _gmx_sel_evaluate_modifier(gmx_sel_evaluate_t                     *data,
                            gmx_ana_index_t                        *g)
 {
     _gmx_sel_evaluate_method_params(data, sel, g);
+    gmx::SelMethodEvalContext context(data->top, data->fr, data->pbc);
     if (sel->flags & SEL_INITFRAME)
     {
         sel->flags &= ~SEL_INITFRAME;
-        sel->u.expr.method->init_frame(data->top, data->fr, data->pbc,
-                                       sel->u.expr.mdata);
+        sel->u.expr.method->init_frame(context, sel->u.expr.mdata);
     }
     if (sel->child && sel->child->v.type != POS_VALUE)
     {
         GMX_THROW(gmx::NotImplementedError("Non-position valued modifiers not implemented"));
     }
-    sel->u.expr.method->pupdate(data->top, data->fr, data->pbc,
-                                NULL, &sel->v, sel->u.expr.mdata);
+    sel->u.expr.method->pupdate(context, NULL, &sel->v, sel->u.expr.mdata);
 }
 
 
index 337e9be336f59b3cbcfdff32d8319d34a29376d0..e2135e2ca2715c038bfc07422da145dadf9ec573 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012,2013,2014, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013,2014,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -52,9 +52,9 @@
 #include "selelem.h"
 
 struct gmx_ana_index_t;
+struct gmx_mtop_t;
 struct gmx_sel_mempool_t;
 struct t_pbc;
-struct t_topology;
 struct t_trxframe;
 
 /*! \internal \brief
@@ -67,7 +67,7 @@ struct gmx_sel_evaluate_t
     /** Index group that contains all the atoms. */
     gmx_ana_index_t          *gall;
     /** Topology information. */
-    t_topology               *top;
+    const gmx_mtop_t         *top;
     /** Current frame. */
     t_trxframe               *fr;
     /** PBC data. */
@@ -81,7 +81,7 @@ struct gmx_sel_evaluate_t
 void
 _gmx_sel_evaluate_init(gmx_sel_evaluate_t *data,
                        gmx_sel_mempool_t *mp, gmx_ana_index_t *gall,
-                       t_topology *top, t_trxframe *fr, t_pbc *pbc);
+                       const gmx_mtop_t *top, t_trxframe *fr, t_pbc *pbc);
 /** Evaluates the children of a general selection element. */
 void
 _gmx_sel_evaluate_children(gmx_sel_evaluate_t                     *data,
index beb5fd8481e4d7c74151f3c9e13fb815ecb7650d..210d52d97bceb0f5afa9379c2836e8fa75a09c12 100644 (file)
@@ -52,6 +52,8 @@
 
 #include "gromacs/topology/block.h"
 #include "gromacs/topology/index.h"
+#include "gromacs/topology/mtop_lookup.h"
+#include "gromacs/topology/mtop_util.h"
 #include "gromacs/topology/topology.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
@@ -105,7 +107,7 @@ struct gmx_ana_indexgrps_t
  * If both are null, the index group structure is initialized empty.
  */
 void
-gmx_ana_indexgrps_init(gmx_ana_indexgrps_t **g, t_topology *top,
+gmx_ana_indexgrps_init(gmx_ana_indexgrps_t **g, gmx_mtop_t *top,
                        const char *fnm)
 {
     t_blocka *block = NULL;
@@ -118,7 +120,10 @@ gmx_ana_indexgrps_init(gmx_ana_indexgrps_t **g, t_topology *top,
     else if (top)
     {
         block = new_blocka();
-        analyse(&top->atoms, block, &names, FALSE, FALSE);
+        // TODO: Propagate mtop further.
+        t_atoms atoms = gmx_mtop_global_atoms(top);
+        analyse(&atoms, block, &names, FALSE, FALSE);
+        done_atom(&atoms);
     }
     else
     {
@@ -140,7 +145,7 @@ gmx_ana_indexgrps_init(gmx_ana_indexgrps_t **g, t_topology *top,
                 grp->index[j] = block->a[block->index[i]+j];
             }
             grp->nalloc_index = grp->isize;
-            (*g)->names.push_back(names[i]);
+            (*g)->names.emplace_back(names[i]);
         }
     }
     catch (...)
@@ -791,7 +796,7 @@ gmx_ana_index_merge(gmx_ana_index_t *dest,
  * \ingroup module_selection
  */
 static bool
-next_group_index(int atomIndex, t_topology *top, e_index_t type, int *id)
+next_group_index(int atomIndex, const gmx_mtop_t *top, e_index_t type, int *id)
 {
     int prev = *id;
     switch (type)
@@ -800,8 +805,12 @@ next_group_index(int atomIndex, t_topology *top, e_index_t type, int *id)
             *id = atomIndex;
             break;
         case INDEX_RES:
-            *id = top->atoms.atom[atomIndex].resind;
+        {
+            int resind, molb = 0;
+            mtopGetAtomAndResidueName(top, atomIndex, &molb, nullptr, nullptr, nullptr, &resind);
+            *id = resind;
             break;
+        }
         case INDEX_MOL:
             if (*id >= 0 && top->mols.index[*id] > atomIndex)
             {
@@ -838,7 +847,7 @@ next_group_index(int atomIndex, t_topology *top, e_index_t type, int *id)
  * \p g should be sorted.
  */
 void
-gmx_ana_index_make_block(t_blocka *t, t_topology *top, gmx_ana_index_t *g,
+gmx_ana_index_make_block(t_blocka *t, const gmx_mtop_t *top, gmx_ana_index_t *g,
                          e_index_t type, bool bComplete)
 {
     if (type == INDEX_UNKNOWN)
@@ -875,10 +884,10 @@ gmx_ana_index_make_block(t_blocka *t, t_topology *top, gmx_ana_index_t *g,
         t->nra = 0;
         /* We may allocate some extra memory here because we don't know in
          * advance how much will be needed. */
-        if (t->nalloc_a < top->atoms.nr)
+        if (t->nalloc_a < top->natoms)
         {
-            srenew(t->a, top->atoms.nr);
-            t->nalloc_a = top->atoms.nr;
+            srenew(t->a, top->natoms);
+            t->nalloc_a = top->natoms;
         }
     }
     else
@@ -902,13 +911,14 @@ gmx_ana_index_make_block(t_blocka *t, t_topology *top, gmx_ana_index_t *g,
     }
     /* Clear counters */
     t->nr  = 0;
-    int j  = 0; /* j is used by residue completion for the first atom not stored */
-    int id = -1;
+    int id   = -1;
+    int molb = 0;
     for (int i = 0; i < g->isize; ++i)
     {
+        const int ai = g->index[i];
         /* Find the ID number of the atom/residue/molecule corresponding to
          * the atom. */
-        if (next_group_index(g->index[i], top, type, &id))
+        if (next_group_index(ai, top, type, &id))
         {
             /* If this is the first atom in a new block, initialize the block. */
             if (bComplete)
@@ -919,19 +929,34 @@ gmx_ana_index_make_block(t_blocka *t, t_topology *top, gmx_ana_index_t *g,
                 switch (type)
                 {
                     case INDEX_RES:
-                        while (top->atoms.atom[j].resind != id)
+                    {
+                        int            molnr, atnr_mol;
+                        mtopGetMolblockIndex(top, ai, &molb, &molnr, &atnr_mol);
+                        const t_atoms &mol_atoms = top->moltype[top->molblock[molb].type].atoms;
+                        int            last_atom = atnr_mol + 1;
+                        while (last_atom < mol_atoms.nr
+                               && mol_atoms.atom[last_atom].resind == id)
+                        {
+                            ++last_atom;
+                        }
+                        int first_atom = atnr_mol - 1;
+                        while (first_atom >= 0
+                               && mol_atoms.atom[first_atom].resind == id)
                         {
-                            ++j;
+                            --first_atom;
                         }
-                        while (j < top->atoms.nr && top->atoms.atom[j].resind == id)
+                        int first_mol_atom = top->molblock[molb].globalAtomStart;
+                        first_mol_atom += molnr*top->molblock[molb].natoms_mol;
+                        first_atom      = first_mol_atom + first_atom + 1;
+                        last_atom       = first_mol_atom + last_atom - 1;
+                        for (int j = first_atom; j <= last_atom; ++j)
                         {
                             t->a[t->nra++] = j;
-                            ++j;
                         }
                         break;
-
+                    }
                     case INDEX_MOL:
-                        for (j = top->mols.index[id]; j < top->mols.index[id+1]; ++j)
+                        for (int j = top->mols.index[id]; j < top->mols.index[id+1]; ++j)
                         {
                             t->a[t->nra++] = j;
                         }
@@ -970,7 +995,7 @@ gmx_ana_index_make_block(t_blocka *t, t_topology *top, gmx_ana_index_t *g,
  * The atoms in \p g are assumed to be sorted.
  */
 bool
-gmx_ana_index_has_full_blocks(gmx_ana_index_t *g, t_block *b)
+gmx_ana_index_has_full_blocks(const gmx_ana_index_t *g, const t_block *b)
 {
     int  i, j, bi;
 
@@ -1043,6 +1068,29 @@ gmx_ana_index_has_full_ablocks(gmx_ana_index_t *g, t_blocka *b)
     return true;
 }
 
+/*!
+ * \brief Returns if an atom is at a residue boundary.
+ *
+ * \param[in]     top   Topology data.
+ * \param[in]     a     Atom index to check, should be -1 <= \p a < top->natoms.
+ * \param[in,out] molb  The molecule block of atom a
+ * \returns       true if atoms \p a and \p a + 1 are in different residues, false otherwise.
+ */
+static bool is_at_residue_boundary(const gmx_mtop_t *top, int a, int *molb)
+{
+    if (a == -1 || a + 1 == top->natoms)
+    {
+        return true;
+    }
+    int resindA;
+    mtopGetAtomAndResidueName(top, a, molb,
+                              nullptr, nullptr, nullptr, &resindA);
+    int resindAPlusOne;
+    mtopGetAtomAndResidueName(top, a + 1, molb,
+                              nullptr, nullptr, nullptr, &resindAPlusOne);
+    return resindAPlusOne != resindA;
+}
+
 /*!
  * \param[in] g     Index group to check.
  * \param[in] type  Block data to check against.
@@ -1058,8 +1106,13 @@ gmx_ana_index_has_full_ablocks(gmx_ana_index_t *g, t_blocka *b)
  */
 bool
 gmx_ana_index_has_complete_elems(gmx_ana_index_t *g, e_index_t type,
-                                 t_topology *top)
+                                 const gmx_mtop_t *top)
 {
+    if (g->isize == 0)
+    {
+        return true;
+    }
+
     // TODO: Consider whether unsorted groups need to be supported better.
     switch (type)
     {
@@ -1072,30 +1125,28 @@ gmx_ana_index_has_complete_elems(gmx_ana_index_t *g, e_index_t type,
 
         case INDEX_RES:
         {
-            int      i, ai;
-            int      id, prev;
-
-            prev = -1;
-            for (i = 0; i < g->isize; ++i)
+            int molb  = 0;
+            int aPrev = -1;
+            for (int i = 0; i < g->isize; ++i)
             {
-                ai = g->index[i];
-                id = top->atoms.atom[ai].resind;
-                if (id != prev)
+                const int a = g->index[i];
+                // Check if a is consecutive or on a residue boundary
+                if (a != aPrev + 1)
                 {
-                    if (ai > 0 && top->atoms.atom[ai-1].resind == id)
+                    if (!is_at_residue_boundary(top, aPrev, &molb))
                     {
                         return false;
                     }
-                    if (i > 0 && g->index[i-1] < top->atoms.nr - 1
-                        && top->atoms.atom[g->index[i-1]+1].resind == prev)
+                    if (!is_at_residue_boundary(top, a - 1, &molb))
                     {
                         return false;
                     }
                 }
-                prev = id;
+                aPrev = a;
             }
-            if (g->index[i-1] < top->atoms.nr - 1
-                && top->atoms.atom[g->index[i-1]+1].resind == prev)
+            GMX_ASSERT(g->isize > 0, "We return above when isize=0");
+            const int a = g->index[g->isize - 1];
+            if (!is_at_residue_boundary(top, a, &molb))
             {
                 return false;
             }
@@ -1176,7 +1227,7 @@ gmx_ana_indexmap_reserve(gmx_ana_indexmap_t *m, int nr, int isize)
  */
 void
 gmx_ana_indexmap_init(gmx_ana_indexmap_t *m, gmx_ana_index_t *g,
-                      t_topology *top, e_index_t type)
+                      const gmx_mtop_t *top, e_index_t type)
 {
     m->type   = type;
     gmx_ana_index_make_block(&m->b, top, g, type, false);
@@ -1198,7 +1249,7 @@ gmx_ana_indexmap_init(gmx_ana_indexmap_t *m, gmx_ana_index_t *g,
 }
 
 int
-gmx_ana_indexmap_init_orgid_group(gmx_ana_indexmap_t *m, t_topology *top,
+gmx_ana_indexmap_init_orgid_group(gmx_ana_indexmap_t *m, const gmx_mtop_t *top,
                                   e_index_t type)
 {
     GMX_RELEASE_ASSERT(m->bStatic,
index 0203515ffcf9bc564efd66806d2d96f7f7f70db8..83de646fef75fc555b8e83c5ea72a81816100367 100644 (file)
@@ -72,7 +72,7 @@ namespace gmx
 class TextWriter;
 }
 
-struct t_topology;
+struct gmx_mtop_t;
 
 /** Stores a set of index groups. */
 struct gmx_ana_indexgrps_t;
@@ -186,7 +186,7 @@ struct gmx_ana_indexmap_t
 /*@{*/
 /** Reads index groups from a file or constructs them from topology. */
 void
-gmx_ana_indexgrps_init(gmx_ana_indexgrps_t **g, t_topology *top,
+gmx_ana_indexgrps_init(gmx_ana_indexgrps_t **g, gmx_mtop_t *top,
                        const char *fnm);
 /** Frees memory allocated for index groups. */
 void
@@ -327,17 +327,18 @@ gmx_ana_index_partition(gmx_ana_index_t *dest1, gmx_ana_index_t *dest2,
 /*@{*/
 /** Partition a group based on topology information. */
 void
-gmx_ana_index_make_block(t_blocka *t, t_topology *top, gmx_ana_index_t *g,
+gmx_ana_index_make_block(t_blocka *t, const gmx_mtop_t *top, gmx_ana_index_t *g,
                          e_index_t type, bool bComplete);
 /** Checks whether a group consists of full blocks. */
 bool
-gmx_ana_index_has_full_blocks(gmx_ana_index_t *g, t_block *b);
+gmx_ana_index_has_full_blocks(const gmx_ana_index_t *g, const t_block *b);
 /** Checks whether a group consists of full blocks. */
 bool
 gmx_ana_index_has_full_ablocks(gmx_ana_index_t *g, t_blocka *b);
 /** Checks whether a group consists of full residues/molecules. */
 bool
-gmx_ana_index_has_complete_elems(gmx_ana_index_t *g, e_index_t type, t_topology *top);
+gmx_ana_index_has_complete_elems(gmx_ana_index_t *g, e_index_t type,
+                                 const gmx_mtop_t *top);
 
 /** Initializes an empty index group mapping. */
 void
@@ -348,7 +349,7 @@ gmx_ana_indexmap_reserve(gmx_ana_indexmap_t *m, int nr, int isize);
 /** Initializes an index group mapping. */
 void
 gmx_ana_indexmap_init(gmx_ana_indexmap_t *m, gmx_ana_index_t *g,
-                      t_topology *top, e_index_t type);
+                      const gmx_mtop_t *top, e_index_t type);
 /*! \brief
  * Initializes `orgid` entries based on topology grouping.
  *
@@ -374,7 +375,7 @@ gmx_ana_indexmap_init(gmx_ana_indexmap_t *m, gmx_ana_index_t *g,
  * Strong exception safety guarantee.
  */
 int
-gmx_ana_indexmap_init_orgid_group(gmx_ana_indexmap_t *m, t_topology *top,
+gmx_ana_indexmap_init_orgid_group(gmx_ana_indexmap_t *m, const gmx_mtop_t *top,
                                   e_index_t type);
 /** Sets an index group mapping to be static. */
 void
index b65af7c791c0066dc00007c3f9c8ac639984d1b5..49471388783a6487da6ab8d78850a3567a08bca3 100644 (file)
@@ -1,19 +1,19 @@
-/* A Bison parser, made by GNU Bison 2.7.12-4996.  */
+/* A Bison parser, made by GNU Bison 3.0.4.  */
 
 /* Bison implementation for Yacc-like parsers in C
-   
-      Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
-   
+
+   Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
+
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
-   
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
@@ -26,7 +26,7 @@
    special exception, which will cause the skeleton and the resulting
    Bison output files to be licensed under the GNU General Public
    License without this special exception.
-   
+
    This special exception was added by the Free Software Foundation in
    version 2.2 of Bison.  */
 
@@ -44,7 +44,7 @@
 #define YYBISON 1
 
 /* Bison version.  */
-#define YYBISON_VERSION "2.7.12-4996"
+#define YYBISON_VERSION "3.0.4"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -59,8 +59,7 @@
 #define YYPULL 0
 
 /* "%code top" blocks.  */
-/* Line 349 of yacc.c  */
-#line 43 "parser.y"
+#line 43 "parser.y" /* yacc.c:316  */
 
 /*! \internal \file parser.cpp
  * \brief Generated (from parser.y by Bison) parser for the selection language.
@@ -74,9 +73,7 @@
  */
 #include "gmxpre.h"
 
-
-/* Line 349 of yacc.c  */
-#line 80 "parser.cpp"
+#line 77 "parser.cpp" /* yacc.c:316  */
 
 /* Substitute the variable and function names.  */
 #define yypush_parse    _gmx_sel_yypush_parse
 #define yypstate        _gmx_sel_yypstate
 #define yylex           _gmx_sel_yylex
 #define yyerror         _gmx_sel_yyerror
-#define yylval          _gmx_sel_yylval
-#define yychar          _gmx_sel_yychar
 #define yydebug         _gmx_sel_yydebug
 #define yynerrs         _gmx_sel_yynerrs
-#define yylloc          _gmx_sel_yylloc
+
 
 /* Copy the first part of user declarations.  */
-/* Line 371 of yacc.c  */
-#line 56 "parser.y"
+#line 56 "parser.y" /* yacc.c:339  */
 
 #include "gromacs/utility/scoped_cptr.h"
 
@@ -113,14 +107,13 @@ using gmx::SelectionTreeElementPointer;
 #pragma warning(disable: 4065)
 #endif
 
-/* Line 371 of yacc.c  */
-#line 118 "parser.cpp"
+#line 111 "parser.cpp" /* yacc.c:339  */
 
-# ifndef YY_NULL
+# ifndef YY_NULLPTR
 #  if defined __cplusplus && 201103L <= __cplusplus
-#   define YY_NULL nullptr
+#   define YY_NULLPTR nullptr
 #  else
-#   define YY_NULL 0
+#   define YY_NULLPTR 0
 #  endif
 # endif
 
@@ -136,7 +129,7 @@ using gmx::SelectionTreeElementPointer;
    by #include "parser.h".  */
 #ifndef YY__GMX_SEL_YY_PARSER_H_INCLUDED
 # define YY__GMX_SEL_YY_PARSER_H_INCLUDED
-/* Enabling traces.  */
+/* Debug traces.  */
 #ifndef YYDEBUG
 # define YYDEBUG 1
 #endif
@@ -144,13 +137,12 @@ using gmx::SelectionTreeElementPointer;
 extern int _gmx_sel_yydebug;
 #endif
 /* "%code requires" blocks.  */
-/* Line 387 of yacc.c  */
-#line 1 "parser.y"
+#line 1 "parser.y" /* yacc.c:355  */
 
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -181,65 +173,60 @@ extern int _gmx_sel_yydebug;
  * To help us fund GROMACS development, we humbly ask that you cite
  * the research papers on the package. Check out http://www.gromacs.org.
  */
-
-/* Line 387 of yacc.c  */
-#line 76 "parser.y"
+#line 76 "parser.y" /* yacc.c:355  */
 
 #include "parsetree.h"
 #include "selelem.h"
 
 #define YYLTYPE ::gmx::SelectionLocation
 
+#line 184 "parser.cpp" /* yacc.c:355  */
 
-/* Line 387 of yacc.c  */
-#line 196 "parser.cpp"
-
-/* Tokens.  */
+/* Token type.  */
 #ifndef YYTOKENTYPE
 # define YYTOKENTYPE
-   /* Put the tokens into the symbol table, so that GDB and other debuggers
-      know about them.  */
-   enum yytokentype {
-     INVALID = 258,
-     TOK_INT = 259,
-     TOK_REAL = 260,
-     STR = 261,
-     IDENTIFIER = 262,
-     CMD_SEP = 263,
-     GROUP = 264,
-     TO = 265,
-     VARIABLE_NUMERIC = 266,
-     VARIABLE_GROUP = 267,
-     VARIABLE_POS = 268,
-     KEYWORD_NUMERIC = 269,
-     KEYWORD_STR = 270,
-     KEYWORD_POS = 271,
-     KEYWORD_GROUP = 272,
-     METHOD_NUMERIC = 273,
-     METHOD_GROUP = 274,
-     METHOD_POS = 275,
-     MODIFIER = 276,
-     EMPTY_POSMOD = 277,
-     PARAM = 278,
-     END_OF_METHOD = 279,
-     OF = 280,
-     CMP_OP = 281,
-     PARAM_REDUCT = 282,
-     XOR = 283,
-     OR = 284,
-     AND = 285,
-     NOT = 286,
-     UNARY_NEG = 287,
-     NUM_REDUCT = 288
-   };
+  enum yytokentype
+  {
+    INVALID = 258,
+    TOK_INT = 259,
+    TOK_REAL = 260,
+    STR = 261,
+    IDENTIFIER = 262,
+    CMD_SEP = 263,
+    GROUP = 264,
+    TO = 265,
+    VARIABLE_NUMERIC = 266,
+    VARIABLE_GROUP = 267,
+    VARIABLE_POS = 268,
+    KEYWORD_NUMERIC = 269,
+    KEYWORD_STR = 270,
+    KEYWORD_POS = 271,
+    KEYWORD_GROUP = 272,
+    METHOD_NUMERIC = 273,
+    METHOD_GROUP = 274,
+    METHOD_POS = 275,
+    MODIFIER = 276,
+    EMPTY_POSMOD = 277,
+    PARAM = 278,
+    END_OF_METHOD = 279,
+    OF = 280,
+    CMP_OP = 281,
+    PARAM_REDUCT = 282,
+    OR = 283,
+    XOR = 284,
+    AND = 285,
+    NOT = 286,
+    UNARY_NEG = 287,
+    NUM_REDUCT = 288
+  };
 #endif
 
-
+/* Value type.  */
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
+
+union YYSTYPE
 {
-/* Line 387 of yacc.c  */
-#line 83 "parser.y"
+#line 83 "parser.y" /* yacc.c:355  */
 
     int                         i;
     real                        r;
@@ -254,29 +241,30 @@ typedef union YYSTYPE
     gmx::SelectionParserParameter               *param;
     gmx::SelectionParserParameterListPointer    *plist;
 
+#line 245 "parser.cpp" /* yacc.c:355  */
+};
 
-/* Line 387 of yacc.c  */
-#line 260 "parser.cpp"
-} YYSTYPE;
+typedef union YYSTYPE YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
 #endif
 
+/* Location type.  */
 #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
-typedef struct YYLTYPE
+typedef struct YYLTYPE YYLTYPE;
+struct YYLTYPE
 {
   int first_line;
   int first_column;
   int last_line;
   int last_column;
-} YYLTYPE;
-# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
+};
 # define YYLTYPE_IS_DECLARED 1
 # define YYLTYPE_IS_TRIVIAL 1
 #endif
 
 
+
 #ifndef YYPUSH_MORE_DEFINED
 # define YYPUSH_MORE_DEFINED
 enum { YYPUSH_MORE = 4 };
@@ -284,29 +272,16 @@ enum { YYPUSH_MORE = 4 };
 
 typedef struct _gmx_sel_yypstate _gmx_sel_yypstate;
 
-#if defined __STDC__ || defined __cplusplus
 int _gmx_sel_yypush_parse (_gmx_sel_yypstate *ps, int pushed_char, YYSTYPE const *pushed_val, YYLTYPE *pushed_loc, void *scanner);
-#else
-int _gmx_sel_yypush_parse ();
-#endif
 
-#if defined __STDC__ || defined __cplusplus
 _gmx_sel_yypstate * _gmx_sel_yypstate_new (void);
-#else
-_gmx_sel_yypstate * _gmx_sel_yypstate_new ();
-#endif
-#if defined __STDC__ || defined __cplusplus
 void _gmx_sel_yypstate_delete (_gmx_sel_yypstate *ps);
-#else
-void _gmx_sel_yypstate_delete ();
-#endif
 
 #endif /* !YY__GMX_SEL_YY_PARSER_H_INCLUDED  */
 
 /* Copy the second part of user declarations.  */
 
-/* Line 390 of yacc.c  */
-#line 310 "parser.cpp"
+#line 285 "parser.cpp" /* yacc.c:358  */
 
 #ifdef short
 # undef short
@@ -320,11 +295,8 @@ typedef unsigned char yytype_uint8;
 
 #ifdef YYTYPE_INT8
 typedef YYTYPE_INT8 yytype_int8;
-#elif (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-typedef signed char yytype_int8;
 #else
-typedef short int yytype_int8;
+typedef signed char yytype_int8;
 #endif
 
 #ifdef YYTYPE_UINT16
@@ -344,8 +316,7 @@ typedef short int yytype_int16;
 #  define YYSIZE_T __SIZE_TYPE__
 # elif defined size_t
 #  define YYSIZE_T size_t
-# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
+# elif ! defined YYSIZE_T
 #  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
 #  define YYSIZE_T size_t
 # else
@@ -367,11 +338,30 @@ typedef short int yytype_int16;
 # endif
 #endif
 
-#ifndef __attribute__
-/* This feature is available in gcc versions 2.5 and later.  */
-# if (! defined __GNUC__ || __GNUC__ < 2 \
-      || (__GNUC__ == 2 && __GNUC_MINOR__ < 5))
-#  define __attribute__(Spec) /* empty */
+#ifndef YY_ATTRIBUTE
+# if (defined __GNUC__                                               \
+      && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__)))  \
+     || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C
+#  define YY_ATTRIBUTE(Spec) __attribute__(Spec)
+# else
+#  define YY_ATTRIBUTE(Spec) /* empty */
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE_PURE
+# define YY_ATTRIBUTE_PURE   YY_ATTRIBUTE ((__pure__))
+#endif
+
+#ifndef YY_ATTRIBUTE_UNUSED
+# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__))
+#endif
+
+#if !defined _Noreturn \
+     && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112)
+# if defined _MSC_VER && 1200 <= _MSC_VER
+#  define _Noreturn __declspec (noreturn)
+# else
+#  define _Noreturn YY_ATTRIBUTE ((__noreturn__))
 # endif
 #endif
 
@@ -382,32 +372,33 @@ typedef short int yytype_int16;
 # define YYUSE(E) /* empty */
 #endif
 
-
-/* Identity function, used to suppress warnings about constant conditions.  */
-#ifndef lint
-# define YYID(N) (N)
-#else
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static int
-YYID (int yyi)
+#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
+/* Suppress an incorrect diagnostic about yylval being uninitialized.  */
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+    _Pragma ("GCC diagnostic push") \
+    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
+    _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+    _Pragma ("GCC diagnostic pop")
 #else
-static int
-YYID (yyi)
-    int yyi;
+# define YY_INITIAL_VALUE(Value) Value
 #endif
-{
-  return yyi;
-}
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
 #endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
 
 #if ! defined yyoverflow || YYERROR_VERBOSE
 
 /* The parser invokes alloca or malloc; define the necessary symbols.  */
 
 # ifdef YYSTACK_ALLOC
-   /* Pacify GCC's `empty if-body' warning.  */
-#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+   /* Pacify GCC's 'empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
 #  ifndef YYSTACK_ALLOC_MAXIMUM
     /* The OS might guarantee only one guard page at the bottom of the stack,
        and a page size can be as small as 4096 bytes.  So we cannot safely
@@ -423,7 +414,7 @@ YYID (yyi)
 #  endif
 #  if (defined __cplusplus && ! defined EXIT_SUCCESS \
        && ! ((defined YYMALLOC || defined malloc) \
-            && (defined YYFREE || defined free)))
+             && (defined YYFREE || defined free)))
 #   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
 #   ifndef EXIT_SUCCESS
 #    define EXIT_SUCCESS 0
@@ -431,15 +422,13 @@ YYID (yyi)
 #  endif
 #  ifndef YYMALLOC
 #   define YYMALLOC malloc
-#   if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
+#   if ! defined malloc && ! defined EXIT_SUCCESS
 void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
 #   endif
 #  endif
 #  ifndef YYFREE
 #   define YYFREE free
-#   if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
+#   if ! defined free && ! defined EXIT_SUCCESS
 void free (void *); /* INFRINGES ON USER NAME SPACE */
 #   endif
 #  endif
@@ -449,8 +438,8 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */
 
 #if (! defined yyoverflow \
      && (! defined __cplusplus || defined GMX_YYFORCE_C_STACK_EXTENSION \
-        || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
-            && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+         || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
+             && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
 
 /* A type that is properly aligned for any stack member.  */
 union yyalloc
@@ -476,16 +465,16 @@ union yyalloc
    elements in the stack, and YYPTR gives the new location of the
    stack.  Advance YYPTR to a properly aligned location for the next
    stack.  */
-# define YYSTACK_RELOCATE(Stack_alloc, Stack)                          \
-    do                                                                 \
-      {                                                                        \
-       YYSIZE_T yynewbytes;                                            \
-       YYCOPY (&yyptr->Stack_alloc, Stack, yysize);                    \
-       Stack = &yyptr->Stack_alloc;                                    \
-       yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
-       yyptr += yynewbytes / sizeof (*yyptr);                          \
-      }                                                                        \
-    while (YYID (0))
+# define YYSTACK_RELOCATE(Stack_alloc, Stack)                           \
+    do                                                                  \
+      {                                                                 \
+        YYSIZE_T yynewbytes;                                            \
+        YYCOPY (&yyptr->Stack_alloc, Stack, yysize);                    \
+        Stack = &yyptr->Stack_alloc;                                    \
+        yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+        yyptr += yynewbytes / sizeof (*yyptr);                          \
+      }                                                                 \
+    while (0)
 
 #endif
 
@@ -504,7 +493,7 @@ union yyalloc
           for (yyi = 0; yyi < (Count); yyi++)   \
             (Dst)[yyi] = (Src)[yyi];            \
         }                                       \
-      while (YYID (0))
+      while (0)
 #  endif
 # endif
 #endif /* !YYCOPY_NEEDED */
@@ -520,17 +509,19 @@ union yyalloc
 #define YYNNTS  25
 /* YYNRULES -- Number of rules.  */
 #define YYNRULES  90
-/* YYNRULES -- Number of states.  */
+/* YYNSTATES -- Number of states.  */
 #define YYNSTATES  154
 
-/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
+   by yylex, with out-of-bounds checking.  */
 #define YYUNDEFTOK  2
 #define YYMAXUTOK   288
 
-#define YYTRANSLATE(YYX)                                               \
+#define YYTRANSLATE(YYX)                                                \
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
 
-/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
+   as returned by yylex, without out-of-bounds checking.  */
 static const yytype_uint8 yytranslate[] =
 {
        0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -565,67 +556,19 @@ static const yytype_uint8 yytranslate[] =
 };
 
 #if YYDEBUG
-/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
-   YYRHS.  */
-static const yytype_uint16 yyprhs[] =
-{
-       0,     0,     3,     4,     7,    10,    13,    14,    16,    18,
-      20,    23,    27,    31,    35,    37,    39,    43,    47,    49,
-      52,    54,    57,    59,    61,    63,    65,    68,    72,    76,
-      80,    84,    87,    90,    92,    94,    96,    98,   100,   103,
-     107,   112,   116,   120,   122,   124,   127,   132,   136,   140,
-     144,   148,   152,   155,   159,   163,   165,   168,   176,   180,
-     183,   187,   189,   191,   193,   195,   198,   199,   202,   205,
-     207,   211,   212,   215,   219,   221,   225,   227,   230,   234,
-     236,   238,   240,   242,   244,   246,   248,   250,   252,   256,
-     260
-};
-
-/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
-static const yytype_int8 yyrhs[] =
-{
-      50,     0,    -1,    -1,    50,    51,    -1,    52,     8,    -1,
-       1,     8,    -1,    -1,     4,    -1,    57,    -1,    53,    -1,
-       6,    53,    -1,     7,    39,    58,    -1,     7,    39,    61,
-      -1,     7,    39,    63,    -1,    63,    -1,    58,    -1,    40,
-      53,    41,    -1,    53,    21,    64,    -1,     4,    -1,    33,
-       4,    -1,     5,    -1,    33,     5,    -1,    54,    -1,    55,
-      -1,     6,    -1,     7,    -1,    31,    58,    -1,    58,    30,
-      58,    -1,    58,    29,    58,    -1,    40,    58,    41,    -1,
-      61,    26,    61,    -1,     9,    57,    -1,     9,     4,    -1,
-      22,    -1,    16,    -1,    42,    -1,    43,    -1,    39,    -1,
-      59,    17,    -1,    59,    15,    69,    -1,    59,    15,    60,
-      69,    -1,    59,    14,    69,    -1,    59,    19,    64,    -1,
-       4,    -1,     5,    -1,    59,    14,    -1,    59,    14,    25,
-      63,    -1,    59,    18,    64,    -1,    61,    32,    61,    -1,
-      61,    33,    61,    -1,    61,    34,    61,    -1,    61,    35,
-      61,    -1,    33,    61,    -1,    61,    37,    61,    -1,    40,
-      61,    41,    -1,    57,    -1,    59,    15,    -1,    44,    56,
-      45,    56,    45,    56,    46,    -1,    40,    63,    41,    -1,
-      20,    64,    -1,    16,    25,    58,    -1,    12,    -1,    11,
-      -1,    13,    -1,    65,    -1,    65,    24,    -1,    -1,    65,
-      66,    -1,    23,    67,    -1,    68,    -1,    47,    68,    48,
-      -1,    -1,    68,    71,    -1,    68,    45,    71,    -1,    70,
-      -1,    47,    70,    48,    -1,    72,    -1,    70,    72,    -1,
-      70,    45,    72,    -1,    58,    -1,    63,    -1,    61,    -1,
-      62,    -1,    73,    -1,    54,    -1,    55,    -1,    57,    -1,
-      73,    -1,    54,    10,    54,    -1,    54,    10,    55,    -1,
-      55,    10,    56,    -1
-};
-
-/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+  /* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   199,   199,   204,   215,   216,   236,   241,   252,   264,
-     270,   277,   284,   291,   301,   302,   309,   310,   324,   325,
-     329,   330,   333,   334,   337,   338,   346,   357,   368,   379,
-     383,   394,   401,   410,   411,   416,   417,   418,   422,   430,
-     438,   446,   457,   472,   483,   497,   505,   513,   524,   530,
-     536,   542,   548,   554,   560,   567,   578,   593,   602,   606,
-     616,   630,   638,   646,   659,   661,   667,   672,   683,   692,
-     693,   698,   703,   711,   722,   723,   727,   733,   741,   751,
-     757,   763,   769,   775,   779,   785,   791,   798,   802,   808,
-     814
+       0,   199,   199,   204,   217,   218,   238,   243,   254,   266,
+     272,   279,   286,   293,   303,   304,   311,   312,   326,   327,
+     331,   332,   335,   336,   339,   340,   348,   359,   370,   381,
+     385,   396,   403,   412,   413,   418,   419,   420,   424,   432,
+     440,   448,   459,   474,   485,   499,   507,   515,   526,   532,
+     538,   544,   550,   556,   562,   569,   580,   595,   604,   608,
+     618,   632,   640,   648,   661,   663,   669,   674,   685,   694,
+     695,   700,   705,   713,   724,   725,   729,   735,   743,   753,
+     759,   765,   771,   777,   781,   787,   793,   800,   804,   810,
+     816
 };
 #endif
 
@@ -639,7 +582,7 @@ static const char *const yytname[] =
   "VARIABLE_GROUP", "VARIABLE_POS", "KEYWORD_NUMERIC", "KEYWORD_STR",
   "KEYWORD_POS", "KEYWORD_GROUP", "METHOD_NUMERIC", "METHOD_GROUP",
   "METHOD_POS", "MODIFIER", "EMPTY_POSMOD", "PARAM", "END_OF_METHOD", "OF",
-  "CMP_OP", "PARAM_REDUCT", "XOR", "OR", "AND", "NOT", "'+'", "'-'", "'*'",
+  "CMP_OP", "PARAM_REDUCT", "OR", "XOR", "AND", "NOT", "'+'", "'-'", "'*'",
   "'/'", "UNARY_NEG", "'^'", "NUM_REDUCT", "'='", "'('", "')'", "'~'",
   "'?'", "'['", "','", "']'", "'{'", "'}'", "$accept", "commands",
   "command", "cmd_plain", "selection", "integer_number", "real_number",
@@ -647,13 +590,13 @@ static const char *const yytname[] =
   "str_expr", "pos_expr", "method_params", "method_param_list",
   "method_param", "value_list", "value_list_contents", "basic_value_list",
   "basic_value_list_contents", "value_item", "basic_value_item",
-  "value_item_range", YY_NULL
+  "value_item_range", YY_NULLPTR
 };
 #endif
 
 # ifdef YYPRINT
-/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
-   token YYLEX-NUM.  */
+/* YYTOKNUM[NUM] -- (External) token number corresponding to the
+   (internal) symbol number NUM (which must be that of a token).  */
 static const yytype_uint16 yytoknum[] =
 {
        0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
@@ -664,39 +607,41 @@ static const yytype_uint16 yytoknum[] =
 };
 # endif
 
-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
-static const yytype_uint8 yyr1[] =
-{
-       0,    49,    50,    50,    51,    51,    52,    52,    52,    52,
-      52,    52,    52,    52,    53,    53,    53,    53,    54,    54,
-      55,    55,    56,    56,    57,    57,    58,    58,    58,    58,
-      58,    58,    58,    59,    59,    60,    60,    60,    58,    58,
-      58,    58,    58,    61,    61,    61,    61,    61,    61,    61,
-      61,    61,    61,    61,    61,    62,    62,    63,    63,    63,
-      63,    58,    61,    63,    64,    64,    65,    65,    66,    67,
-      67,    68,    68,    68,    69,    69,    70,    70,    70,    71,
-      71,    71,    71,    71,    72,    72,    72,    72,    73,    73,
-      73
-};
+#define YYPACT_NINF -85
 
-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
-static const yytype_uint8 yyr2[] =
+#define yypact_value_is_default(Yystate) \
+  (!!((Yystate) == (-85)))
+
+#define YYTABLE_NINF -22
+
+#define yytable_value_is_error(Yytable_value) \
+  0
+
+  /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+     STATE-NUM.  */
+static const yytype_int16 yypact[] =
 {
-       0,     2,     0,     2,     2,     2,     0,     1,     1,     1,
-       2,     3,     3,     3,     1,     1,     3,     3,     1,     2,
-       1,     2,     1,     1,     1,     1,     2,     3,     3,     3,
-       3,     2,     2,     1,     1,     1,     1,     1,     2,     3,
-       4,     3,     3,     1,     1,     2,     4,     3,     3,     3,
-       3,     3,     2,     3,     3,     1,     2,     7,     3,     2,
-       3,     1,     1,     1,     1,     2,     0,     2,     2,     1,
-       3,     0,     2,     3,     1,     3,     1,     2,     3,     1,
-       1,     1,     1,     1,     1,     1,     1,     1,     3,     3,
-       3
+     -85,    10,   -85,    -2,    26,   -85,   273,     0,    55,   -85,
+     -85,   -85,    40,   -85,   -85,   310,   204,   273,    69,   -85,
+      62,    82,   -85,    -3,   139,   312,   -85,   -85,   -85,    82,
+     296,   -85,   -85,   -85,   -85,   310,   -85,    96,   -85,   310,
+     -85,   204,    -6,    73,    15,    71,   220,    67,   -85,   -85,
+     135,   -85,   -85,    83,   -85,   -85,   310,   310,    41,   185,
+     -85,   -85,   -85,   204,   204,   204,   204,   204,   204,   296,
+      -3,   312,   -85,    -3,    97,   -85,   -85,    71,   319,    91,
+     -85,   -85,   -85,   -85,   -85,   -85,    69,   -85,   113,   -85,
+      24,   206,   137,   140,   -85,   -85,    90,   -85,   -85,   -85,
+     -85,   -85,    85,   -85,   -85,   -85,   330,   167,   167,    73,
+      73,    73,    67,   -85,   -85,   229,   107,    40,    24,   -85,
+     174,    69,    69,   206,   -85,   -85,   155,   153,   159,   326,
+     259,   137,   140,   -85,    -3,   179,   330,   -85,   -85,   -85,
+     -85,    69,   -85,   -85,   -85,   -85,   -85,   -85,   160,   164,
+     -85,   185,   119,   -85
 };
 
-/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
-   Performed when YYTABLE doesn't specify something else to do.  Zero
-   means the default is an error.  */
+  /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+     Performed when YYTABLE does not specify something else to do.  Zero
+     means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
        2,     0,     1,     0,    43,    44,    24,    25,     0,    62,
@@ -717,7 +662,15 @@ static const yytype_uint8 yydefact[] =
       73,    56,     0,    57
 };
 
-/* YYDEFGOTO[NTERM-NUM].  */
+  /* YYPGOTO[NTERM-NUM].  */
+static const yytype_int8 yypgoto[] =
+{
+     -85,   -85,   -85,   -85,     7,   -17,   -15,   -84,    -1,   116,
+      19,   -85,    12,   -85,     3,    75,   -85,   -85,   -85,    63,
+     -53,    92,    52,   -65,   -63
+};
+
+  /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int16 yydefgoto[] =
 {
       -1,     1,    19,    20,    21,    92,    93,    53,    94,   134,
@@ -725,69 +678,37 @@ static const yytype_int16 yydefgoto[] =
      103,    96,   139,    97,    98
 };
 
-/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
-   STATE-NUM.  */
-#define YYPACT_NINF -85
-static const yytype_int16 yypact[] =
-{
-     -85,    10,   -85,    -2,    17,   -85,   273,   -12,    55,   -85,
-     -85,   -85,     9,   -85,   -85,   310,   204,   273,    69,   -85,
-      31,    44,   -85,   110,   179,   312,   -85,   -85,   -85,    44,
-     296,   -85,   -85,   -85,   -85,   310,   -85,    96,   -85,   310,
-     -85,   204,    -6,    33,    15,   124,   220,    58,   -85,   -85,
-     139,   -85,   -85,    56,   -85,   -85,   310,   310,    41,   185,
-     -85,   -85,   -85,   204,   204,   204,   204,   204,   204,   296,
-     110,   312,   -85,   110,    61,   -85,   -85,   124,   319,    78,
-     -85,   -85,   -85,   -85,   -85,   -85,    69,   -85,    80,   -85,
-      24,   206,   102,   106,   -85,   -85,    90,   -85,   -85,   -85,
-     -85,   -85,    85,   -85,   -85,   -85,   330,   213,   213,    33,
-      33,    33,    58,   -85,   -85,   229,    83,     9,    24,   -85,
-     174,    69,    69,   206,   -85,   -85,   155,   137,   140,   326,
-     259,   102,   106,   -85,   110,   187,   330,   -85,   -85,   -85,
-     -85,    69,   -85,   -85,   -85,   -85,   -85,   -85,   142,   146,
-     -85,   185,   111,   -85
-};
-
-/* YYPGOTO[NTERM-NUM].  */
-static const yytype_int8 yypgoto[] =
-{
-     -85,   -85,   -85,   -85,     7,   -17,   -15,   -84,    -1,   116,
-      19,   -85,    12,   -85,     3,    75,   -85,   -85,   -85,    45,
-     -53,    72,    39,   -65,   -63
-};
-
-/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
-   positive, shift that token.  If negative, reduce the rule which
-   number is the opposite.  If YYTABLE_NINF, syntax error.  */
-#define YYTABLE_NINF -22
+  /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
+     positive, shift that token.  If negative, reduce the rule whose
+     number is the opposite.  If YYTABLE_NINF, syntax error.  */
 static const yytype_int16 yytable[] =
 {
       22,    51,   116,    52,    26,    95,    27,    34,    79,    26,
        2,     3,    61,    29,     4,     5,     6,     7,    -6,     8,
-      47,     9,    10,    11,    44,    -7,    12,    30,    43,    46,
-      13,   124,    14,    72,    35,    42,    55,    11,   145,    54,
+      47,     9,    10,    11,    44,    56,    12,    57,    43,    46,
+      13,   124,    14,    72,    -7,    42,    55,    11,   145,    30,
      117,    15,    71,    16,    13,    48,    49,    32,    33,   125,
       17,    46,   140,    78,    18,   124,    80,   152,   146,    31,
-      42,    32,    33,   140,   118,    55,    90,   140,    18,    51,
-      68,    52,   112,    48,    49,   106,   107,   108,   109,   110,
+      42,    32,    33,   140,   118,    35,    90,   140,    18,    51,
+      54,    52,   112,    48,    49,   106,   107,   108,   109,   110,
      111,    46,    42,    42,    42,    42,    42,    42,    91,    48,
-      49,    32,    33,   119,    48,    49,    32,    33,   131,    83,
-     132,    86,    50,    90,   143,    51,   144,    52,   113,   131,
-      57,   132,   121,   131,   133,   132,   122,    23,    50,    74,
-      75,   112,    23,    50,    51,   133,    52,   136,   141,   133,
-      87,    40,    91,    45,   135,   123,   104,   105,   136,    56,
-      57,    43,   136,    84,    85,   135,    70,   -18,    42,   135,
-     -20,    73,   -19,    56,    57,    77,   -21,   153,   126,   127,
-     128,    32,    33,   120,     8,    81,     9,    10,    11,   150,
-       0,    12,    88,    89,     0,    13,     0,    14,    48,    49,
-      32,    33,     0,     0,     0,    77,    15,     0,   129,    48,
-      49,    32,    33,    58,    59,    69,    60,    61,    62,    18,
-     130,    58,   151,   147,    60,    61,    62,    50,    28,     5,
+      49,    32,    33,   119,    48,    49,    32,    33,   131,    56,
+     132,    57,    50,    55,   143,    51,   144,    52,    83,   131,
+      68,   132,    81,   131,   133,   132,    90,    23,    50,    74,
+      75,   112,    23,    50,    51,   133,    52,   136,    86,   133,
+      87,    40,    91,    45,   135,   123,   104,   105,   136,    84,
+      85,    43,   136,    57,   113,   135,    70,   121,    42,   135,
+     122,    73,   141,    58,    59,    77,    60,    61,    62,   127,
+     128,    32,    33,   -18,     8,   153,     9,    10,    11,   -20,
+     -19,    12,    88,    89,   -21,    13,   126,    14,    48,    49,
+      32,    33,   150,   120,     0,    77,    15,     0,   129,    48,
+      49,    32,    33,    58,   151,    69,    60,    61,    62,    18,
+     130,    66,    67,   147,    68,     0,     0,    50,    28,     5,
       48,    49,    32,    33,     0,     9,     0,     0,    50,   123,
       38,     0,   142,     0,    99,     0,    14,   100,   101,     0,
        0,     0,    91,   127,   128,    32,    33,    16,     8,    50,
-       9,    10,    11,     0,    41,    12,    63,    66,    67,    13,
-      68,    14,    64,    65,    66,    67,     0,    68,     0,     0,
+       9,    10,    11,     0,    41,    12,    63,     0,     0,    13,
+       0,    14,    64,    65,    66,    67,     0,    68,     0,     0,
       15,    82,   129,   127,   128,    32,    33,     0,     8,    69,
        9,    10,    11,    18,   130,    12,     0,    28,     5,    13,
        0,    14,     8,     0,     9,    10,    11,     0,     0,    12,
@@ -801,40 +722,34 @@ static const yytype_int16 yytable[] =
       82,     0,    64,    65,    66,    67,    41,    68
 };
 
-#define yypact_value_is_default(Yystate) \
-  (!!((Yystate) == (-85)))
-
-#define yytable_value_is_error(Yytable_value) \
-  YYID (0)
-
 static const yytype_int16 yycheck[] =
 {
        1,    18,    86,    18,     1,    58,     8,     8,    14,     6,
        0,     1,    18,     6,     4,     5,     6,     7,     8,     9,
-      17,    11,    12,    13,    17,     8,    16,    39,    16,    17,
-      20,    96,    22,    30,    25,    16,    21,    13,   122,     8,
+      17,    11,    12,    13,    17,    28,    16,    30,    16,    17,
+      20,    96,    22,    30,     8,    16,    21,    13,   122,    39,
       16,    31,    30,    33,    20,     4,     5,     6,     7,   102,
       40,    39,   115,    41,    44,   120,    41,   141,   123,     4,
-      41,     6,     7,   126,    40,    21,    25,   130,    44,    86,
-      37,    86,    69,     4,     5,    63,    64,    65,    66,    67,
+      41,     6,     7,   126,    40,    25,    25,   130,    44,    86,
+       8,    86,    69,     4,     5,    63,    64,    65,    66,    67,
       68,    69,    63,    64,    65,    66,    67,    68,    47,     4,
-       5,     6,     7,    90,     4,     5,     6,     7,   115,    41,
-     115,    45,    33,    25,   121,   122,   121,   122,    47,   126,
-      30,   126,    10,   130,   115,   130,    10,     1,    33,    23,
+       5,     6,     7,    90,     4,     5,     6,     7,   115,    28,
+     115,    30,    33,    21,   121,   122,   121,   122,    41,   126,
+      37,   126,    41,   130,   115,   130,    25,     1,    33,    23,
       24,   118,     6,    33,   141,   126,   141,   115,    45,   130,
-      55,    15,    47,    17,   115,    45,    61,    62,   126,    29,
-      30,   129,   130,     4,     5,   126,    30,    10,   129,   130,
-      10,    35,    10,    29,    30,    39,    10,    46,   113,     4,
-       5,     6,     7,    91,     9,    41,    11,    12,    13,   130,
-      -1,    16,    56,    57,    -1,    20,    -1,    22,     4,     5,
-       6,     7,    -1,    -1,    -1,    69,    31,    -1,    33,     4,
+      55,    15,    47,    17,   115,    45,    61,    62,   126,     4,
+       5,   129,   130,    30,    47,   126,    30,    10,   129,   130,
+      10,    35,    45,    14,    15,    39,    17,    18,    19,     4,
+       5,     6,     7,    10,     9,    46,    11,    12,    13,    10,
+      10,    16,    56,    57,    10,    20,   113,    22,     4,     5,
+       6,     7,   130,    91,    -1,    69,    31,    -1,    33,     4,
        5,     6,     7,    14,    15,    40,    17,    18,    19,    44,
-      45,    14,    15,    48,    17,    18,    19,    33,     4,     5,
+      45,    34,    35,    48,    37,    -1,    -1,    33,     4,     5,
        4,     5,     6,     7,    -1,    11,    -1,    -1,    33,    45,
       16,    -1,    48,    -1,    39,    -1,    22,    42,    43,    -1,
       -1,    -1,    47,     4,     5,     6,     7,    33,     9,    33,
-      11,    12,    13,    -1,    40,    16,    26,    34,    35,    20,
-      37,    22,    32,    33,    34,    35,    -1,    37,    -1,    -1,
+      11,    12,    13,    -1,    40,    16,    26,    -1,    -1,    20,
+      -1,    22,    32,    33,    34,    35,    -1,    37,    -1,    -1,
       31,    41,    33,     4,     5,     6,     7,    -1,     9,    40,
       11,    12,    13,    44,    45,    16,    -1,     4,     5,    20,
       -1,    22,     9,    -1,    11,    12,    13,    -1,    -1,    16,
@@ -848,8 +763,8 @@ static const yytype_int16 yycheck[] =
       41,    -1,    32,    33,    34,    35,    40,    37
 };
 
-/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
-   symbol of state STATE-NUM.  */
+  /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+     symbol of state STATE-NUM.  */
 static const yytype_uint8 yystos[] =
 {
        0,    50,     0,     1,     4,     5,     6,     7,     9,    11,
@@ -857,7 +772,7 @@ static const yytype_uint8 yystos[] =
       52,    53,    57,    58,    59,    61,    63,     8,     4,    53,
       39,     4,     6,     7,    57,    25,    64,    65,    16,    40,
       58,    40,    59,    61,    53,    58,    61,    63,     4,     5,
-      33,    54,    55,    56,     8,    21,    29,    30,    14,    15,
+      33,    54,    55,    56,     8,    21,    28,    30,    14,    15,
       17,    18,    19,    26,    32,    33,    34,    35,    37,    40,
       58,    61,    63,    58,    23,    24,    66,    58,    61,    14,
       41,    41,    41,    41,     4,     5,    45,    64,    58,    58,
@@ -870,30 +785,46 @@ static const yytype_uint8 yystos[] =
       71,    15,    56,    46
 };
 
-#define yyerrok                (yyerrstatus = 0)
-#define yyclearin      (yychar = YYEMPTY)
-#define YYEMPTY                (-2)
-#define YYEOF          0
-
-#define YYACCEPT       goto yyacceptlab
-#define YYABORT                goto yyabortlab
-#define YYERROR                goto yyerrorlab
-
-
-/* Like YYERROR except do call yyerror.  This remains here temporarily
-   to ease the transition to the new meaning of YYERROR, for GCC.
-   Once GCC version 2 has supplanted version 1, this can go.  However,
-   YYFAIL appears to be in use.  Nevertheless, it is formally deprecated
-   in Bison 2.4.2's NEWS entry, where a plan to phase it out is
-   discussed.  */
-
-#define YYFAIL         goto yyerrlab
-#if defined YYFAIL
-  /* This is here to suppress warnings from the GCC cpp's
-     -Wunused-macros.  Normally we don't worry about that warning, but
-     some users do, and we want to make it easy for users to remove
-     YYFAIL uses, which will produce warnings from Bison 2.5.  */
-#endif
+  /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,    49,    50,    50,    51,    51,    52,    52,    52,    52,
+      52,    52,    52,    52,    53,    53,    53,    53,    54,    54,
+      55,    55,    56,    56,    57,    57,    58,    58,    58,    58,
+      58,    58,    58,    59,    59,    60,    60,    60,    58,    58,
+      58,    58,    58,    61,    61,    61,    61,    61,    61,    61,
+      61,    61,    61,    61,    61,    62,    62,    63,    63,    63,
+      63,    58,    61,    63,    64,    64,    65,    65,    66,    67,
+      67,    68,    68,    68,    69,    69,    70,    70,    70,    71,
+      71,    71,    71,    71,    72,    72,    72,    72,    73,    73,
+      73
+};
+
+  /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     0,     2,     2,     2,     0,     1,     1,     1,
+       2,     3,     3,     3,     1,     1,     3,     3,     1,     2,
+       1,     2,     1,     1,     1,     1,     2,     3,     3,     3,
+       3,     2,     2,     1,     1,     1,     1,     1,     2,     3,
+       4,     3,     3,     1,     1,     2,     4,     3,     3,     3,
+       3,     3,     2,     3,     3,     1,     2,     7,     3,     2,
+       3,     1,     1,     1,     1,     2,     0,     2,     2,     1,
+       3,     0,     2,     3,     1,     3,     1,     2,     3,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     3,     3,
+       3
+};
+
+
+#define yyerrok         (yyerrstatus = 0)
+#define yyclearin       (yychar = YYEMPTY)
+#define YYEMPTY         (-2)
+#define YYEOF           0
+
+#define YYACCEPT        goto yyacceptlab
+#define YYABORT         goto yyabortlab
+#define YYERROR         goto yyerrorlab
+
 
 #define YYRECOVERING()  (!!yyerrstatus)
 
@@ -910,13 +841,13 @@ do                                                              \
   else                                                          \
     {                                                           \
       yyerror (&yylloc, scanner, YY_("syntax error: cannot back up")); \
-      YYERROR;                                                 \
-    }                                                          \
-while (YYID (0))
+      YYERROR;                                                  \
+    }                                                           \
+while (0)
 
 /* Error token number */
-#define YYTERROR       1
-#define YYERRCODE      256
+#define YYTERROR        1
+#define YYERRCODE       256
 
 
 /* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
@@ -926,7 +857,7 @@ while (YYID (0))
 #ifndef YYLLOC_DEFAULT
 # define YYLLOC_DEFAULT(Current, Rhs, N)                                \
     do                                                                  \
-      if (YYID (N))                                                     \
+      if (N)                                                            \
         {                                                               \
           (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;        \
           (Current).first_column = YYRHSLOC (Rhs, 1).first_column;      \
@@ -940,12 +871,27 @@ while (YYID (0))
           (Current).first_column = (Current).last_column =              \
             YYRHSLOC (Rhs, 0).last_column;                              \
         }                                                               \
-    while (YYID (0))
+    while (0)
 #endif
 
 #define YYRHSLOC(Rhs, K) ((Rhs)[K])
 
 
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)                        \
+do {                                            \
+  if (yydebug)                                  \
+    YYFPRINTF Args;                             \
+} while (0)
+
+
 /* YY_LOCATION_PRINT -- Print the location on the stream.
    This macro was not mandated originally: define only if we know
    we won't break user code: when these are the locations we know.  */
@@ -955,36 +901,28 @@ while (YYID (0))
 
 /* Print *YYLOCP on YYO.  Private, do not rely on its existence. */
 
-__attribute__((__unused__))
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
+YY_ATTRIBUTE_UNUSED
 static unsigned
 yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp)
-#else
-static unsigned
-yy_location_print_ (yyo, yylocp)
-    FILE *yyo;
-    YYLTYPE const * const yylocp;
-#endif
 {
   unsigned res = 0;
   int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0;
   if (0 <= yylocp->first_line)
     {
-      res += fprintf (yyo, "%d", yylocp->first_line);
+      res += YYFPRINTF (yyo, "%d", yylocp->first_line);
       if (0 <= yylocp->first_column)
-        res += fprintf (yyo, ".%d", yylocp->first_column);
+        res += YYFPRINTF (yyo, ".%d", yylocp->first_column);
     }
   if (0 <= yylocp->last_line)
     {
       if (yylocp->first_line < yylocp->last_line)
         {
-          res += fprintf (yyo, "-%d", yylocp->last_line);
+          res += YYFPRINTF (yyo, "-%d", yylocp->last_line);
           if (0 <= end_col)
-            res += fprintf (yyo, ".%d", end_col);
+            res += YYFPRINTF (yyo, ".%d", end_col);
         }
       else if (0 <= end_col && yylocp->first_column < end_col)
-        res += fprintf (yyo, "-%d", end_col);
+        res += YYFPRINTF (yyo, "-%d", end_col);
     }
   return res;
  }
@@ -998,69 +936,34 @@ yy_location_print_ (yyo, yylocp)
 #endif
 
 
-/* YYLEX -- calling `yylex' with the right arguments.  */
-#ifdef YYLEX_PARAM
-# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM)
-#else
-# define YYLEX yylex (&yylval, &yylloc)
-#endif
-
-/* Enable debugging if requested.  */
-#if YYDEBUG
-
-# ifndef YYFPRINTF
-#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
-#  define YYFPRINTF fprintf
-# endif
-
-# define YYDPRINTF(Args)                       \
-do {                                           \
-  if (yydebug)                                 \
-    YYFPRINTF Args;                            \
-} while (YYID (0))
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)                    \
+do {                                                                      \
+  if (yydebug)                                                            \
+    {                                                                     \
+      YYFPRINTF (stderr, "%s ", Title);                                   \
+      yy_symbol_print (stderr,                                            \
+                  Type, Value, Location, scanner); \
+      YYFPRINTF (stderr, "\n");                                           \
+    }                                                                     \
+} while (0)
 
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)                   \
-do {                                                                     \
-  if (yydebug)                                                           \
-    {                                                                    \
-      YYFPRINTF (stderr, "%s ", Title);                                          \
-      yy_symbol_print (stderr,                                           \
-                 Type, Value, Location, scanner); \
-      YYFPRINTF (stderr, "\n");                                                  \
-    }                                                                    \
-} while (YYID (0))
 
+/*----------------------------------------.
+| Print this symbol's value on YYOUTPUT.  |
+`----------------------------------------*/
 
-/*--------------------------------.
-| Print this symbol on YYOUTPUT.  |
-`--------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
 static void
 yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, void *scanner)
-#else
-static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, scanner)
-    FILE *yyoutput;
-    int yytype;
-    YYSTYPE const * const yyvaluep;
-    YYLTYPE const * const yylocationp;
-    void *scanner;
-#endif
 {
   FILE *yyo gmx_unused = yyoutput;
   YYUSE (yyo);
-  if (!yyvaluep)
-    return;
   YYUSE (yylocationp);
   YYUSE (scanner);
+  if (!yyvaluep)
+    return;
 # ifdef YYPRINT
   if (yytype < YYNTOKENS)
     YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# else
-  YYUSE (yyoutput);
 # endif
   YYUSE (yytype);
 }
@@ -1070,24 +973,11 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, scanner)
 | Print this symbol on YYOUTPUT.  |
 `--------------------------------*/
 
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
 static void
 yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, void *scanner)
-#else
-static void
-yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, scanner)
-    FILE *yyoutput;
-    int yytype;
-    YYSTYPE const * const yyvaluep;
-    YYLTYPE const * const yylocationp;
-    void *scanner;
-#endif
 {
-  if (yytype < YYNTOKENS)
-    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
-  else
-    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+  YYFPRINTF (yyoutput, "%s %s (",
+             yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]);
 
   YY_LOCATION_PRINT (yyoutput, *yylocationp);
   YYFPRINTF (yyoutput, ": ");
@@ -1100,16 +990,8 @@ yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, scanner)
 | TOP (included).                                                   |
 `------------------------------------------------------------------*/
 
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
 static void
 yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
-#else
-static void
-yy_stack_print (yybottom, yytop)
-    yytype_int16 *yybottom;
-    yytype_int16 *yytop;
-#endif
 {
   YYFPRINTF (stderr, "Stack now");
   for (; yybottom <= yytop; yybottom++)
@@ -1120,51 +1002,42 @@ yy_stack_print (yybottom, yytop)
   YYFPRINTF (stderr, "\n");
 }
 
-# define YY_STACK_PRINT(Bottom, Top)                           \
-do {                                                           \
-  if (yydebug)                                                 \
-    yy_stack_print ((Bottom), (Top));                          \
-} while (YYID (0))
+# define YY_STACK_PRINT(Bottom, Top)                            \
+do {                                                            \
+  if (yydebug)                                                  \
+    yy_stack_print ((Bottom), (Top));                           \
+} while (0)
 
 
 /*------------------------------------------------.
 | Report that the YYRULE is going to be reduced.  |
 `------------------------------------------------*/
 
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, void *scanner)
-#else
 static void
-yy_reduce_print (yyvsp, yylsp, yyrule, scanner)
-    YYSTYPE *yyvsp;
-    YYLTYPE *yylsp;
-    int yyrule;
-    void *scanner;
-#endif
+yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, void *scanner)
 {
+  unsigned long int yylno = yyrline[yyrule];
   int yynrhs = yyr2[yyrule];
   int yyi;
-  unsigned long int yylno = yyrline[yyrule];
   YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
-            yyrule - 1, yylno);
+             yyrule - 1, yylno);
   /* The symbols being reduced.  */
   for (yyi = 0; yyi < yynrhs; yyi++)
     {
       YYFPRINTF (stderr, "   $%d = ", yyi + 1);
-      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
-                      &(yyvsp[(yyi + 1) - (yynrhs)])
-                      , &(yylsp[(yyi + 1) - (yynrhs)])                , scanner);
+      yy_symbol_print (stderr,
+                       yystos[yyssp[yyi + 1 - yynrhs]],
+                       &(yyvsp[(yyi + 1) - (yynrhs)])
+                       , &(yylsp[(yyi + 1) - (yynrhs)])                       , scanner);
       YYFPRINTF (stderr, "\n");
     }
 }
 
-# define YY_REDUCE_PRINT(Rule)         \
-do {                                   \
-  if (yydebug)                         \
-    yy_reduce_print (yyvsp, yylsp, Rule, scanner); \
-} while (YYID (0))
+# define YY_REDUCE_PRINT(Rule)          \
+do {                                    \
+  if (yydebug)                          \
+    yy_reduce_print (yyssp, yyvsp, yylsp, Rule, scanner); \
+} while (0)
 
 /* Nonzero means print parse trace.  It is left uninitialized so that
    multiple parsers can coexist.  */
@@ -1178,7 +1051,7 @@ int yydebug;
 
 
 /* YYINITDEPTH -- initial size of the parser's stacks.  */
-#ifndef        YYINITDEPTH
+#ifndef YYINITDEPTH
 # define YYINITDEPTH 200
 #endif
 
@@ -1201,15 +1074,8 @@ int yydebug;
 #   define yystrlen strlen
 #  else
 /* Return the length of YYSTR.  */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
 static YYSIZE_T
 yystrlen (const char *yystr)
-#else
-static YYSIZE_T
-yystrlen (yystr)
-    const char *yystr;
-#endif
 {
   YYSIZE_T yylen;
   for (yylen = 0; yystr[yylen]; yylen++)
@@ -1225,16 +1091,8 @@ yystrlen (yystr)
 #  else
 /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
    YYDEST.  */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
 static char *
 yystpcpy (char *yydest, const char *yysrc)
-#else
-static char *
-yystpcpy (yydest, yysrc)
-    char *yydest;
-    const char *yysrc;
-#endif
 {
   char *yyd = yydest;
   const char *yys = yysrc;
@@ -1264,27 +1122,27 @@ yytnamerr (char *yyres, const char *yystr)
       char const *yyp = yystr;
 
       for (;;)
-       switch (*++yyp)
-         {
-         case '\'':
-         case ',':
-           goto do_not_strip_quotes;
-
-         case '\\':
-           if (*++yyp != '\\')
-             goto do_not_strip_quotes;
-           /* Fall through.  */
-         default:
-           if (yyres)
-             yyres[yyn] = *yyp;
-           yyn++;
-           break;
-
-         case '"':
-           if (yyres)
-             yyres[yyn] = '\0';
-           return yyn;
-         }
+        switch (*++yyp)
+          {
+          case '\'':
+          case ',':
+            goto do_not_strip_quotes;
+
+          case '\\':
+            if (*++yyp != '\\')
+              goto do_not_strip_quotes;
+            /* Fall through.  */
+          default:
+            if (yyres)
+              yyres[yyn] = *yyp;
+            yyn++;
+            break;
+
+          case '"':
+            if (yyres)
+              yyres[yyn] = '\0';
+            return yyn;
+          }
     do_not_strip_quotes: ;
     }
 
@@ -1307,11 +1165,11 @@ static int
 yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
                 yytype_int16 *yyssp, int yytoken)
 {
-  YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]);
+  YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]);
   YYSIZE_T yysize = yysize0;
   enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
   /* Internationalized format string. */
-  const char *yyformat = YY_NULL;
+  const char *yyformat = YY_NULLPTR;
   /* Arguments of yyformat. */
   char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
   /* Number of reported tokens (one for the "unexpected", one per
@@ -1319,10 +1177,6 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
   int yycount = 0;
 
   /* There are many possibilities here to consider:
-     - Assume YYFAIL is not used.  It's too flawed to consider.  See
-       <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
-       for details.  YYERROR is fine as it does not invoke this
-       function.
      - If this state is a consistent state with a default action, then
        the only way this function was invoked is if the default action
        is an error action.  In that case, don't check for expected
@@ -1372,7 +1226,7 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
                   }
                 yyarg[yycount++] = yytname[yyx];
                 {
-                  YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]);
+                  YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]);
                   if (! (yysize <= yysize1
                          && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
                     return 2;
@@ -1439,210 +1293,174 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
 | Release the memory associated to this symbol.  |
 `-----------------------------------------------*/
 
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
 static void
 yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, void *scanner)
-#else
-static void
-yydestruct (yymsg, yytype, yyvaluep, yylocationp, scanner)
-    const char *yymsg;
-    int yytype;
-    YYSTYPE *yyvaluep;
-    YYLTYPE *yylocationp;
-    void *scanner;
-#endif
 {
   YYUSE (yyvaluep);
   YYUSE (yylocationp);
   YYUSE (scanner);
-
   if (!yymsg)
     yymsg = "Deleting";
   YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
 
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   switch (yytype)
     {
-      case 6: /* STR */
-/* Line 1393 of yacc.c  */
-#line 178 "parser.y"
-        { free(((*yyvaluep).str));        };
-/* Line 1393 of yacc.c  */
-#line 1473 "parser.cpp"
+          case 6: /* STR  */
+#line 178 "parser.y" /* yacc.c:1257  */
+      { free(((*yyvaluep).str));        }
+#line 1313 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 7: /* IDENTIFIER */
-/* Line 1393 of yacc.c  */
-#line 178 "parser.y"
-        { free(((*yyvaluep).str));        };
-/* Line 1393 of yacc.c  */
-#line 1480 "parser.cpp"
+
+    case 7: /* IDENTIFIER  */
+#line 178 "parser.y" /* yacc.c:1257  */
+      { free(((*yyvaluep).str));        }
+#line 1319 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 16: /* KEYWORD_POS */
-/* Line 1393 of yacc.c  */
-#line 178 "parser.y"
-        { free(((*yyvaluep).str));        };
-/* Line 1393 of yacc.c  */
-#line 1487 "parser.cpp"
+
+    case 16: /* KEYWORD_POS  */
+#line 178 "parser.y" /* yacc.c:1257  */
+      { free(((*yyvaluep).str));        }
+#line 1325 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 23: /* PARAM */
-/* Line 1393 of yacc.c  */
-#line 179 "parser.y"
-        { if(((*yyvaluep).str)) free(((*yyvaluep).str)); };
-/* Line 1393 of yacc.c  */
-#line 1494 "parser.cpp"
+
+    case 23: /* PARAM  */
+#line 179 "parser.y" /* yacc.c:1257  */
+      { if(((*yyvaluep).str)) free(((*yyvaluep).str)); }
+#line 1331 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 26: /* CMP_OP */
-/* Line 1393 of yacc.c  */
-#line 178 "parser.y"
-        { free(((*yyvaluep).str));        };
-/* Line 1393 of yacc.c  */
-#line 1501 "parser.cpp"
+
+    case 26: /* CMP_OP  */
+#line 178 "parser.y" /* yacc.c:1257  */
+      { free(((*yyvaluep).str));        }
+#line 1337 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 50: /* commands */
-/* Line 1393 of yacc.c  */
-#line 180 "parser.y"
-        { delete ((*yyvaluep).sel);       };
-/* Line 1393 of yacc.c  */
-#line 1508 "parser.cpp"
+
+    case 50: /* commands  */
+#line 180 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).sel);       }
+#line 1343 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 51: /* command */
-/* Line 1393 of yacc.c  */
-#line 180 "parser.y"
-        { delete ((*yyvaluep).sel);       };
-/* Line 1393 of yacc.c  */
-#line 1515 "parser.cpp"
+
+    case 51: /* command  */
+#line 180 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).sel);       }
+#line 1349 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 52: /* cmd_plain */
-/* Line 1393 of yacc.c  */
-#line 180 "parser.y"
-        { delete ((*yyvaluep).sel);       };
-/* Line 1393 of yacc.c  */
-#line 1522 "parser.cpp"
+
+    case 52: /* cmd_plain  */
+#line 180 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).sel);       }
+#line 1355 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 53: /* selection */
-/* Line 1393 of yacc.c  */
-#line 180 "parser.y"
-        { delete ((*yyvaluep).sel);       };
-/* Line 1393 of yacc.c  */
-#line 1529 "parser.cpp"
+
+    case 53: /* selection  */
+#line 180 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).sel);       }
+#line 1361 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 57: /* string */
-/* Line 1393 of yacc.c  */
-#line 178 "parser.y"
-        { free(((*yyvaluep).str));        };
-/* Line 1393 of yacc.c  */
-#line 1536 "parser.cpp"
+
+    case 57: /* string  */
+#line 178 "parser.y" /* yacc.c:1257  */
+      { free(((*yyvaluep).str));        }
+#line 1367 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 58: /* sel_expr */
-/* Line 1393 of yacc.c  */
-#line 181 "parser.y"
-        { delete ((*yyvaluep).sel);       };
-/* Line 1393 of yacc.c  */
-#line 1543 "parser.cpp"
+
+    case 58: /* sel_expr  */
+#line 181 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).sel);       }
+#line 1373 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 59: /* pos_mod */
-/* Line 1393 of yacc.c  */
-#line 179 "parser.y"
-        { if(((*yyvaluep).str)) free(((*yyvaluep).str)); };
-/* Line 1393 of yacc.c  */
-#line 1550 "parser.cpp"
+
+    case 59: /* pos_mod  */
+#line 179 "parser.y" /* yacc.c:1257  */
+      { if(((*yyvaluep).str)) free(((*yyvaluep).str)); }
+#line 1379 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 61: /* num_expr */
-/* Line 1393 of yacc.c  */
-#line 181 "parser.y"
-        { delete ((*yyvaluep).sel);       };
-/* Line 1393 of yacc.c  */
-#line 1557 "parser.cpp"
+
+    case 61: /* num_expr  */
+#line 181 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).sel);       }
+#line 1385 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 62: /* str_expr */
-/* Line 1393 of yacc.c  */
-#line 181 "parser.y"
-        { delete ((*yyvaluep).sel);       };
-/* Line 1393 of yacc.c  */
-#line 1564 "parser.cpp"
+
+    case 62: /* str_expr  */
+#line 181 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).sel);       }
+#line 1391 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 63: /* pos_expr */
-/* Line 1393 of yacc.c  */
-#line 181 "parser.y"
-        { delete ((*yyvaluep).sel);       };
-/* Line 1393 of yacc.c  */
-#line 1571 "parser.cpp"
+
+    case 63: /* pos_expr  */
+#line 181 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).sel);       }
+#line 1397 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 64: /* method_params */
-/* Line 1393 of yacc.c  */
-#line 182 "parser.y"
-        { delete ((*yyvaluep).plist);       };
-/* Line 1393 of yacc.c  */
-#line 1578 "parser.cpp"
+
+    case 64: /* method_params  */
+#line 182 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).plist);       }
+#line 1403 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 65: /* method_param_list */
-/* Line 1393 of yacc.c  */
-#line 182 "parser.y"
-        { delete ((*yyvaluep).plist);       };
-/* Line 1393 of yacc.c  */
-#line 1585 "parser.cpp"
+
+    case 65: /* method_param_list  */
+#line 182 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).plist);       }
+#line 1409 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 66: /* method_param */
-/* Line 1393 of yacc.c  */
-#line 182 "parser.y"
-        { delete ((*yyvaluep).param);       };
-/* Line 1393 of yacc.c  */
-#line 1592 "parser.cpp"
+
+    case 66: /* method_param  */
+#line 182 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).param);       }
+#line 1415 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 67: /* value_list */
-/* Line 1393 of yacc.c  */
-#line 183 "parser.y"
-        { delete ((*yyvaluep).vlist);       };
-/* Line 1393 of yacc.c  */
-#line 1599 "parser.cpp"
+
+    case 67: /* value_list  */
+#line 183 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).vlist);       }
+#line 1421 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 68: /* value_list_contents */
-/* Line 1393 of yacc.c  */
-#line 183 "parser.y"
-        { delete ((*yyvaluep).vlist);       };
-/* Line 1393 of yacc.c  */
-#line 1606 "parser.cpp"
+
+    case 68: /* value_list_contents  */
+#line 183 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).vlist);       }
+#line 1427 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 69: /* basic_value_list */
-/* Line 1393 of yacc.c  */
-#line 183 "parser.y"
-        { delete ((*yyvaluep).vlist);       };
-/* Line 1393 of yacc.c  */
-#line 1613 "parser.cpp"
+
+    case 69: /* basic_value_list  */
+#line 183 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).vlist);       }
+#line 1433 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 70: /* basic_value_list_contents */
-/* Line 1393 of yacc.c  */
-#line 183 "parser.y"
-        { delete ((*yyvaluep).vlist);       };
-/* Line 1393 of yacc.c  */
-#line 1620 "parser.cpp"
+
+    case 70: /* basic_value_list_contents  */
+#line 183 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).vlist);       }
+#line 1439 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 71: /* value_item */
-/* Line 1393 of yacc.c  */
-#line 184 "parser.y"
-        { delete ((*yyvaluep).val);       };
-/* Line 1393 of yacc.c  */
-#line 1627 "parser.cpp"
+
+    case 71: /* value_item  */
+#line 184 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).val);       }
+#line 1445 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 72: /* basic_value_item */
-/* Line 1393 of yacc.c  */
-#line 184 "parser.y"
-        { delete ((*yyvaluep).val);       };
-/* Line 1393 of yacc.c  */
-#line 1634 "parser.cpp"
+
+    case 72: /* basic_value_item  */
+#line 184 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).val);       }
+#line 1451 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 73: /* value_item_range */
-/* Line 1393 of yacc.c  */
-#line 184 "parser.y"
-        { delete ((*yyvaluep).val);       };
-/* Line 1393 of yacc.c  */
-#line 1641 "parser.cpp"
+
+    case 73: /* value_item_range  */
+#line 184 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).val);       }
+#line 1457 "parser.cpp" /* yacc.c:1257  */
         break;
 
+
       default:
         break;
     }
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
 }
 
 
@@ -1657,9 +1475,9 @@ struct yypstate
     int yyerrstatus;
 
     /* The stacks and their tools:
-       `yyss': related to states.
-       `yyvs': related to semantic values.
-       `yyls': related to locations.
+       'yyss': related to states.
+       'yyvs': related to semantic values.
+       'yyls': related to locations.
 
        Refer to the stacks through separate pointers, to allow yyoverflow
        to reallocate them elsewhere.  */
@@ -1689,33 +1507,19 @@ struct yypstate
   };
 
 /* Initialize the parser data structure.  */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
 yypstate *
 yypstate_new (void)
-#else
-yypstate *
-yypstate_new ()
-
-#endif
 {
   yypstate *yyps;
   yyps = (yypstate *) malloc (sizeof *yyps);
   if (!yyps)
-    return YY_NULL;
+    return YY_NULLPTR;
   yyps->yynew = 1;
   return yyps;
 }
 
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
 void
 yypstate_delete (yypstate *yyps)
-#else
-void
-yypstate_delete (yyps)
-    yypstate *yyps;
-#endif
 {
 #ifndef yyoverflow
   /* If the stack was reallocated but the parse did not complete, then the
@@ -1746,58 +1550,27 @@ yypstate_delete (yyps)
 | yypush_parse.  |
 `---------------*/
 
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
 int
 yypush_parse (yypstate *yyps, int yypushed_char, YYSTYPE const *yypushed_val, YYLTYPE *yypushed_loc, void *scanner)
-#else
-int
-yypush_parse (yyps, yypushed_char, yypushed_val, yypushed_loc, scanner)
-    yypstate *yyps;
-    int yypushed_char;
-    YYSTYPE const *yypushed_val;
-    YYLTYPE *yypushed_loc;
-    void *scanner;
-#endif
 {
 /* The lookahead symbol.  */
 int yychar;
 
 
-#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
-/* Suppress an incorrect diagnostic about yylval being uninitialized.  */
-# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
-    _Pragma ("GCC diagnostic push") \
-    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
-    _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
-# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
-    _Pragma ("GCC diagnostic pop")
-#else
+/* The semantic value of the lookahead symbol.  */
 /* Default value used for initialization, for pacifying older GCCs
    or non-GCC compilers.  */
-static YYSTYPE yyval_default;
-# define YY_INITIAL_VALUE(Value) = Value
-#endif
+YY_INITIAL_VALUE (static YYSTYPE yyval_default;)
+YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default);
+
+/* Location data for the lookahead symbol.  */
 static YYLTYPE yyloc_default
 # if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
   = { 1, 1, 1, 1 }
 # endif
 ;
-#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-# define YY_IGNORE_MAYBE_UNINITIALIZED_END
-#endif
-#ifndef YY_INITIAL_VALUE
-# define YY_INITIAL_VALUE(Value) /* Nothing. */
-#endif
-
-/* The semantic value of the lookahead symbol.  */
-YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
-
-/* Location data for the lookahead symbol.  */
 YYLTYPE yylloc = yyloc_default;
 
-
   int yyn;
   int yyresult;
   /* Lookahead token as an internal (translated) token number.  */
@@ -1858,26 +1631,26 @@ YYLTYPE yylloc = yyloc_default;
 
 #ifdef yyoverflow
       {
-       /* Give user a chance to reallocate the stack.  Use copies of
-          these so that the &'s don't force the real ones into
-          memory.  */
-       YYSTYPE *yyvs1 = yyvs;
-       yytype_int16 *yyss1 = yyss;
-       YYLTYPE *yyls1 = yyls;
-
-       /* Each stack pointer address is followed by the size of the
-          data in use in that stack, in bytes.  This used to be a
-          conditional around just the two extra args, but that might
-          be undefined if yyoverflow is a macro.  */
-       yyoverflow (YY_("memory exhausted"),
-                   &yyss1, yysize * sizeof (*yyssp),
-                   &yyvs1, yysize * sizeof (*yyvsp),
-                   &yyls1, yysize * sizeof (*yylsp),
-                   &yystacksize);
-
-       yyls = yyls1;
-       yyss = yyss1;
-       yyvs = yyvs1;
+        /* Give user a chance to reallocate the stack.  Use copies of
+           these so that the &'s don't force the real ones into
+           memory.  */
+        YYSTYPE *yyvs1 = yyvs;
+        yytype_int16 *yyss1 = yyss;
+        YYLTYPE *yyls1 = yyls;
+
+        /* Each stack pointer address is followed by the size of the
+           data in use in that stack, in bytes.  This used to be a
+           conditional around just the two extra args, but that might
+           be undefined if yyoverflow is a macro.  */
+        yyoverflow (YY_("memory exhausted"),
+                    &yyss1, yysize * sizeof (*yyssp),
+                    &yyvs1, yysize * sizeof (*yyvsp),
+                    &yyls1, yysize * sizeof (*yylsp),
+                    &yystacksize);
+
+        yyls = yyls1;
+        yyss = yyss1;
+        yyvs = yyvs1;
       }
 #else /* no yyoverflow */
 # ifndef YYSTACK_RELOCATE
@@ -1885,23 +1658,23 @@ YYLTYPE yylloc = yyloc_default;
 # else
       /* Extend the stack our own way.  */
       if (YYMAXDEPTH <= yystacksize)
-       goto yyexhaustedlab;
+        goto yyexhaustedlab;
       yystacksize *= 2;
       if (YYMAXDEPTH < yystacksize)
-       yystacksize = YYMAXDEPTH;
+        yystacksize = YYMAXDEPTH;
 
       {
-       yytype_int16 *yyss1 = yyss;
-       union yyalloc *yyptr =
-         (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
-       if (! yyptr)
-         goto yyexhaustedlab;
-       YYSTACK_RELOCATE (yyss_alloc, yyss);
-       YYSTACK_RELOCATE (yyvs_alloc, yyvs);
-       YYSTACK_RELOCATE (yyls_alloc, yyls);
+        yytype_int16 *yyss1 = yyss;
+        union yyalloc *yyptr =
+          (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+        if (! yyptr)
+          goto yyexhaustedlab;
+        YYSTACK_RELOCATE (yyss_alloc, yyss);
+        YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+        YYSTACK_RELOCATE (yyls_alloc, yyls);
 #  undef YYSTACK_RELOCATE
-       if (yyss1 != yyssa)
-         YYSTACK_FREE (yyss1);
+        if (yyss1 != yyssa)
+          YYSTACK_FREE (yyss1);
       }
 # endif
 #endif /* no yyoverflow */
@@ -1911,10 +1684,10 @@ YYLTYPE yylloc = yyloc_default;
       yylsp = yyls + yysize - 1;
 
       YYDPRINTF ((stderr, "Stack size increased to %lu\n",
-                 (unsigned long int) yystacksize));
+                  (unsigned long int) yystacksize));
 
       if (yyss + yystacksize - 1 <= yyssp)
-       YYABORT;
+        YYABORT;
     }
 
   YYDPRINTF ((stderr, "Entering state %d\n", yystate));
@@ -2020,7 +1793,7 @@ yyreduce:
   yylen = yyr2[yyn];
 
   /* If YYLEN is nonzero, implement the default value of the action:
-     `$$ = $1'.
+     '$$ = $1'.
 
      Otherwise, the following line sets YYVAL to garbage.
      This behavior is undocumented and Bison
@@ -2035,36 +1808,37 @@ yyreduce:
   switch (yyn)
     {
         case 2:
-/* Line 1787 of yacc.c  */
-#line 199 "parser.y"
+#line 199 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
                  set_empty((yyval.sel));
                  END_ACTION_TOPLEVEL;
              }
+#line 1818 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 3:
-/* Line 1787 of yacc.c  */
-#line 205 "parser.y"
+#line 205 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_append_selection(get((yyvsp[(2) - (2)].sel)), get((yyvsp[(1) - (2)].sel)), scanner));
-                 if (_gmx_sel_parser_should_finish(scanner))
+                 set((yyval.sel), _gmx_sel_append_selection(get((yyvsp[0].sel)), get((yyvsp[-1].sel)), scanner));
+                 if (_gmx_sel_parser_should_finish(scanner)) {
+                     delete (yyval.sel);
                      YYACCEPT;
+                 }
                  END_ACTION_TOPLEVEL;
              }
+#line 1832 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 4:
-/* Line 1787 of yacc.c  */
-#line 215 "parser.y"
-    { (yyval.sel) = (yyvsp[(1) - (2)].sel); }
+#line 217 "parser.y" /* yacc.c:1646  */
+    { (yyval.sel) = (yyvsp[-1].sel); }
+#line 1838 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 5:
-/* Line 1787 of yacc.c  */
-#line 217 "parser.y"
+#line 219 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
                  _gmx_sel_lexer_clear_method_stack(scanner);
@@ -2080,191 +1854,191 @@ yyreduce:
                  set_empty((yyval.sel));
                  END_ACTION_TOPLEVEL;
              }
+#line 1858 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 6:
-/* Line 1787 of yacc.c  */
-#line 236 "parser.y"
+#line 238 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
                  set_empty((yyval.sel));
                  END_ACTION;
              }
+#line 1868 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 7:
-/* Line 1787 of yacc.c  */
-#line 242 "parser.y"
+#line 244 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer s
-                        = _gmx_sel_init_group_by_id((yyvsp[(1) - (1)].i), scanner);
+                        = _gmx_sel_init_group_by_id((yyvsp[0].i), scanner);
                  SelectionTreeElementPointer p
                         = _gmx_sel_init_position(s, NULL, scanner);
                  if (!p) YYERROR;
                  set((yyval.sel), _gmx_sel_init_selection(NULL, p, scanner));
                  END_ACTION;
              }
+#line 1883 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 8:
-/* Line 1787 of yacc.c  */
-#line 253 "parser.y"
+#line 255 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree nameGuard((yyvsp[(1) - (1)].str));
+                 scoped_guard_sfree nameGuard((yyvsp[0].str));
                  SelectionTreeElementPointer s
-                        = _gmx_sel_init_group_by_name((yyvsp[(1) - (1)].str), scanner);
+                        = _gmx_sel_init_group_by_name((yyvsp[0].str), scanner);
                  SelectionTreeElementPointer p
                         = _gmx_sel_init_position(s, NULL, scanner);
                  if (!p) YYERROR;
                  set((yyval.sel), _gmx_sel_init_selection(NULL, p, scanner));
                  END_ACTION;
              }
+#line 1899 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 9:
-/* Line 1787 of yacc.c  */
-#line 265 "parser.y"
+#line 267 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_selection(NULL, get((yyvsp[(1) - (1)].sel)), scanner));
+                 set((yyval.sel), _gmx_sel_init_selection(NULL, get((yyvsp[0].sel)), scanner));
                  END_ACTION;
              }
+#line 1909 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 10:
-/* Line 1787 of yacc.c  */
-#line 271 "parser.y"
+#line 273 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree nameGuard((yyvsp[(1) - (2)].str));
-                 set((yyval.sel), _gmx_sel_init_selection((yyvsp[(1) - (2)].str), get((yyvsp[(2) - (2)].sel)), scanner));
+                 scoped_guard_sfree nameGuard((yyvsp[-1].str));
+                 set((yyval.sel), _gmx_sel_init_selection((yyvsp[-1].str), get((yyvsp[0].sel)), scanner));
                  END_ACTION;
              }
+#line 1920 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 11:
-/* Line 1787 of yacc.c  */
-#line 278 "parser.y"
+#line 280 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree nameGuard((yyvsp[(1) - (3)].str));
-                 set((yyval.sel), _gmx_sel_assign_variable((yyvsp[(1) - (3)].str), get((yyvsp[(3) - (3)].sel)), scanner));
+                 scoped_guard_sfree nameGuard((yyvsp[-2].str));
+                 set((yyval.sel), _gmx_sel_assign_variable((yyvsp[-2].str), get((yyvsp[0].sel)), scanner));
                  END_ACTION;
              }
+#line 1931 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 12:
-/* Line 1787 of yacc.c  */
-#line 285 "parser.y"
+#line 287 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree nameGuard((yyvsp[(1) - (3)].str));
-                 set((yyval.sel), _gmx_sel_assign_variable((yyvsp[(1) - (3)].str), get((yyvsp[(3) - (3)].sel)), scanner));
+                 scoped_guard_sfree nameGuard((yyvsp[-2].str));
+                 set((yyval.sel), _gmx_sel_assign_variable((yyvsp[-2].str), get((yyvsp[0].sel)), scanner));
                  END_ACTION;
              }
+#line 1942 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 13:
-/* Line 1787 of yacc.c  */
-#line 292 "parser.y"
+#line 294 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree nameGuard((yyvsp[(1) - (3)].str));
-                 set((yyval.sel), _gmx_sel_assign_variable((yyvsp[(1) - (3)].str), get((yyvsp[(3) - (3)].sel)), scanner));
+                 scoped_guard_sfree nameGuard((yyvsp[-2].str));
+                 set((yyval.sel), _gmx_sel_assign_variable((yyvsp[-2].str), get((yyvsp[0].sel)), scanner));
                  END_ACTION;
              }
+#line 1953 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 14:
-/* Line 1787 of yacc.c  */
-#line 301 "parser.y"
-    { (yyval.sel) = (yyvsp[(1) - (1)].sel); }
+#line 303 "parser.y" /* yacc.c:1646  */
+    { (yyval.sel) = (yyvsp[0].sel); }
+#line 1959 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 15:
-/* Line 1787 of yacc.c  */
-#line 303 "parser.y"
+#line 305 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_position(get((yyvsp[(1) - (1)].sel)), NULL, scanner));
+                 set((yyval.sel), _gmx_sel_init_position(get((yyvsp[0].sel)), NULL, scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 1970 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 16:
-/* Line 1787 of yacc.c  */
-#line 309 "parser.y"
-    { (yyval.sel) = (yyvsp[(2) - (3)].sel); }
+#line 311 "parser.y" /* yacc.c:1646  */
+    { (yyval.sel) = (yyvsp[-1].sel); }
+#line 1976 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 17:
-/* Line 1787 of yacc.c  */
-#line 311 "parser.y"
+#line 313 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_modifier((yyvsp[(2) - (3)].meth), get((yyvsp[(3) - (3)].plist)), get((yyvsp[(1) - (3)].sel)), scanner));
+                 set((yyval.sel), _gmx_sel_init_modifier((yyvsp[-1].meth), get((yyvsp[0].plist)), get((yyvsp[-2].sel)), scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 1987 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 18:
-/* Line 1787 of yacc.c  */
-#line 324 "parser.y"
-    { (yyval.i) = (yyvsp[(1) - (1)].i); }
+#line 326 "parser.y" /* yacc.c:1646  */
+    { (yyval.i) = (yyvsp[0].i); }
+#line 1993 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 19:
-/* Line 1787 of yacc.c  */
-#line 325 "parser.y"
-    { (yyval.i) = -(yyvsp[(2) - (2)].i); }
+#line 327 "parser.y" /* yacc.c:1646  */
+    { (yyval.i) = -(yyvsp[0].i); }
+#line 1999 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 20:
-/* Line 1787 of yacc.c  */
-#line 329 "parser.y"
-    { (yyval.r) = (yyvsp[(1) - (1)].r); }
+#line 331 "parser.y" /* yacc.c:1646  */
+    { (yyval.r) = (yyvsp[0].r); }
+#line 2005 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 21:
-/* Line 1787 of yacc.c  */
-#line 330 "parser.y"
-    { (yyval.r) = -(yyvsp[(2) - (2)].r); }
+#line 332 "parser.y" /* yacc.c:1646  */
+    { (yyval.r) = -(yyvsp[0].r); }
+#line 2011 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 22:
-/* Line 1787 of yacc.c  */
-#line 333 "parser.y"
-    { (yyval.r) = (yyvsp[(1) - (1)].i); }
+#line 335 "parser.y" /* yacc.c:1646  */
+    { (yyval.r) = (yyvsp[0].i); }
+#line 2017 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 23:
-/* Line 1787 of yacc.c  */
-#line 334 "parser.y"
-    { (yyval.r) = (yyvsp[(1) - (1)].r); }
+#line 336 "parser.y" /* yacc.c:1646  */
+    { (yyval.r) = (yyvsp[0].r); }
+#line 2023 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 24:
-/* Line 1787 of yacc.c  */
-#line 337 "parser.y"
-    { (yyval.str) = (yyvsp[(1) - (1)].str); }
+#line 339 "parser.y" /* yacc.c:1646  */
+    { (yyval.str) = (yyvsp[0].str); }
+#line 2029 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 25:
-/* Line 1787 of yacc.c  */
-#line 338 "parser.y"
-    { (yyval.str) = (yyvsp[(1) - (1)].str); }
+#line 340 "parser.y" /* yacc.c:1646  */
+    { (yyval.str) = (yyvsp[0].str); }
+#line 2035 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 26:
-/* Line 1787 of yacc.c  */
-#line 347 "parser.y"
+#line 349 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 SelectionTreeElementPointer arg(get((yyvsp[(2) - (2)].sel)));
+                 SelectionTreeElementPointer arg(get((yyvsp[0].sel)));
                  SelectionTreeElementPointer sel(
                         new SelectionTreeElement(SEL_BOOLEAN, (yyloc)));
                  sel->u.boolt = BOOL_NOT;
@@ -2272,14 +2046,14 @@ yyreduce:
                  set((yyval.sel), sel);
                  END_ACTION;
              }
+#line 2050 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 27:
-/* Line 1787 of yacc.c  */
-#line 358 "parser.y"
+#line 360 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 SelectionTreeElementPointer arg1(get((yyvsp[(1) - (3)].sel))), arg2(get((yyvsp[(3) - (3)].sel)));
+                 SelectionTreeElementPointer arg1(get((yyvsp[-2].sel))), arg2(get((yyvsp[0].sel)));
                  SelectionTreeElementPointer sel(
                         new SelectionTreeElement(SEL_BOOLEAN, (yyloc)));
                  sel->u.boolt = BOOL_AND;
@@ -2287,14 +2061,14 @@ yyreduce:
                  set((yyval.sel), sel);
                  END_ACTION;
              }
+#line 2065 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 28:
-/* Line 1787 of yacc.c  */
-#line 369 "parser.y"
+#line 371 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 SelectionTreeElementPointer arg1(get((yyvsp[(1) - (3)].sel))), arg2(get((yyvsp[(3) - (3)].sel)));
+                 SelectionTreeElementPointer arg1(get((yyvsp[-2].sel))), arg2(get((yyvsp[0].sel)));
                  SelectionTreeElementPointer sel(
                         new SelectionTreeElement(SEL_BOOLEAN, (yyloc)));
                  sel->u.boolt = BOOL_OR;
@@ -2302,618 +2076,618 @@ yyreduce:
                  set((yyval.sel), sel);
                  END_ACTION;
              }
+#line 2080 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 29:
-/* Line 1787 of yacc.c  */
-#line 379 "parser.y"
-    { (yyval.sel) = (yyvsp[(2) - (3)].sel); }
+#line 381 "parser.y" /* yacc.c:1646  */
+    { (yyval.sel) = (yyvsp[-1].sel); }
+#line 2086 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 30:
-/* Line 1787 of yacc.c  */
-#line 384 "parser.y"
+#line 386 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree opGuard((yyvsp[(2) - (3)].str));
-                 set((yyval.sel), _gmx_sel_init_comparison(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), (yyvsp[(2) - (3)].str), scanner));
+                 scoped_guard_sfree opGuard((yyvsp[-1].str));
+                 set((yyval.sel), _gmx_sel_init_comparison(get((yyvsp[-2].sel)), get((yyvsp[0].sel)), (yyvsp[-1].str), scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 2098 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 31:
-/* Line 1787 of yacc.c  */
-#line 395 "parser.y"
+#line 397 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree nameGuard((yyvsp[(2) - (2)].str));
-                 set((yyval.sel), _gmx_sel_init_group_by_name((yyvsp[(2) - (2)].str), scanner));
+                 scoped_guard_sfree nameGuard((yyvsp[0].str));
+                 set((yyval.sel), _gmx_sel_init_group_by_name((yyvsp[0].str), scanner));
                  END_ACTION;
              }
+#line 2109 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 32:
-/* Line 1787 of yacc.c  */
-#line 402 "parser.y"
+#line 404 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_group_by_id((yyvsp[(2) - (2)].i), scanner));
+                 set((yyval.sel), _gmx_sel_init_group_by_id((yyvsp[0].i), scanner));
                  END_ACTION;
              }
+#line 2119 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 33:
-/* Line 1787 of yacc.c  */
-#line 410 "parser.y"
+#line 412 "parser.y" /* yacc.c:1646  */
     { (yyval.str) = NULL; }
+#line 2125 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 34:
-/* Line 1787 of yacc.c  */
-#line 411 "parser.y"
-    { (yyval.str) = (yyvsp[(1) - (1)].str);   }
+#line 413 "parser.y" /* yacc.c:1646  */
+    { (yyval.str) = (yyvsp[0].str);   }
+#line 2131 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 35:
-/* Line 1787 of yacc.c  */
-#line 416 "parser.y"
+#line 418 "parser.y" /* yacc.c:1646  */
     { (yyval.smt) = gmx::eStringMatchType_RegularExpression; }
+#line 2137 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 36:
-/* Line 1787 of yacc.c  */
-#line 417 "parser.y"
+#line 419 "parser.y" /* yacc.c:1646  */
     { (yyval.smt) = gmx::eStringMatchType_Wildcard; }
+#line 2143 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 37:
-/* Line 1787 of yacc.c  */
-#line 418 "parser.y"
+#line 420 "parser.y" /* yacc.c:1646  */
     { (yyval.smt) = gmx::eStringMatchType_Exact; }
+#line 2149 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 38:
-/* Line 1787 of yacc.c  */
-#line 423 "parser.y"
+#line 425 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree posmodGuard((yyvsp[(1) - (2)].str));
-                 set((yyval.sel), _gmx_sel_init_keyword((yyvsp[(2) - (2)].meth), SelectionParserValueListPointer(), (yyvsp[(1) - (2)].str), scanner));
+                 scoped_guard_sfree posmodGuard((yyvsp[-1].str));
+                 set((yyval.sel), _gmx_sel_init_keyword((yyvsp[0].meth), SelectionParserValueListPointer(), (yyvsp[-1].str), scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 2161 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 39:
-/* Line 1787 of yacc.c  */
-#line 431 "parser.y"
+#line 433 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree posmodGuard((yyvsp[(1) - (3)].str));
-                 set((yyval.sel), _gmx_sel_init_keyword_strmatch((yyvsp[(2) - (3)].meth), gmx::eStringMatchType_Auto, get((yyvsp[(3) - (3)].vlist)), (yyvsp[(1) - (3)].str), scanner));
+                 scoped_guard_sfree posmodGuard((yyvsp[-2].str));
+                 set((yyval.sel), _gmx_sel_init_keyword_strmatch((yyvsp[-1].meth), gmx::eStringMatchType_Auto, get((yyvsp[0].vlist)), (yyvsp[-2].str), scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 2173 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 40:
-/* Line 1787 of yacc.c  */
-#line 439 "parser.y"
+#line 441 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree posmodGuard((yyvsp[(1) - (4)].str));
-                 set((yyval.sel), _gmx_sel_init_keyword_strmatch((yyvsp[(2) - (4)].meth), (yyvsp[(3) - (4)].smt), get((yyvsp[(4) - (4)].vlist)), (yyvsp[(1) - (4)].str), scanner));
+                 scoped_guard_sfree posmodGuard((yyvsp[-3].str));
+                 set((yyval.sel), _gmx_sel_init_keyword_strmatch((yyvsp[-2].meth), (yyvsp[-1].smt), get((yyvsp[0].vlist)), (yyvsp[-3].str), scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 2185 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 41:
-/* Line 1787 of yacc.c  */
-#line 447 "parser.y"
+#line 449 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree posmodGuard((yyvsp[(1) - (3)].str));
-                 set((yyval.sel), _gmx_sel_init_keyword((yyvsp[(2) - (3)].meth), get((yyvsp[(3) - (3)].vlist)), (yyvsp[(1) - (3)].str), scanner));
+                 scoped_guard_sfree posmodGuard((yyvsp[-2].str));
+                 set((yyval.sel), _gmx_sel_init_keyword((yyvsp[-1].meth), get((yyvsp[0].vlist)), (yyvsp[-2].str), scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 2197 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 42:
-/* Line 1787 of yacc.c  */
-#line 458 "parser.y"
+#line 460 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree posmodGuard((yyvsp[(1) - (3)].str));
-                 set((yyval.sel), _gmx_sel_init_method((yyvsp[(2) - (3)].meth), get((yyvsp[(3) - (3)].plist)), (yyvsp[(1) - (3)].str), scanner));
+                 scoped_guard_sfree posmodGuard((yyvsp[-2].str));
+                 set((yyval.sel), _gmx_sel_init_method((yyvsp[-1].meth), get((yyvsp[0].plist)), (yyvsp[-2].str), scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 2209 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 43:
-/* Line 1787 of yacc.c  */
-#line 473 "parser.y"
+#line 475 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer sel(
                         new SelectionTreeElement(SEL_CONST, (yyloc)));
                  _gmx_selelem_set_vtype(sel, INT_VALUE);
                  _gmx_selvalue_reserve(&sel->v, 1);
-                 sel->v.u.i[0] = (yyvsp[(1) - (1)].i);
+                 sel->v.u.i[0] = (yyvsp[0].i);
                  set((yyval.sel), sel);
                  END_ACTION;
              }
+#line 2224 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 44:
-/* Line 1787 of yacc.c  */
-#line 484 "parser.y"
+#line 486 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer sel(
                         new SelectionTreeElement(SEL_CONST, (yyloc)));
                  _gmx_selelem_set_vtype(sel, REAL_VALUE);
                  _gmx_selvalue_reserve(&sel->v, 1);
-                 sel->v.u.r[0] = (yyvsp[(1) - (1)].r);
+                 sel->v.u.r[0] = (yyvsp[0].r);
                  set((yyval.sel), sel);
                  END_ACTION;
              }
+#line 2239 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 45:
-/* Line 1787 of yacc.c  */
-#line 498 "parser.y"
+#line 500 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree posmodGuard((yyvsp[(1) - (2)].str));
-                 set((yyval.sel), _gmx_sel_init_keyword((yyvsp[(2) - (2)].meth), SelectionParserValueListPointer(), (yyvsp[(1) - (2)].str), scanner));
+                 scoped_guard_sfree posmodGuard((yyvsp[-1].str));
+                 set((yyval.sel), _gmx_sel_init_keyword((yyvsp[0].meth), SelectionParserValueListPointer(), (yyvsp[-1].str), scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 2251 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 46:
-/* Line 1787 of yacc.c  */
-#line 506 "parser.y"
+#line 508 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree posmodGuard((yyvsp[(1) - (4)].str));
-                 set((yyval.sel), _gmx_sel_init_keyword_of((yyvsp[(2) - (4)].meth), get((yyvsp[(4) - (4)].sel)), (yyvsp[(1) - (4)].str), scanner));
+                 scoped_guard_sfree posmodGuard((yyvsp[-3].str));
+                 set((yyval.sel), _gmx_sel_init_keyword_of((yyvsp[-2].meth), get((yyvsp[0].sel)), (yyvsp[-3].str), scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 2263 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 47:
-/* Line 1787 of yacc.c  */
-#line 514 "parser.y"
+#line 516 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree posmodGuard((yyvsp[(1) - (3)].str));
-                 set((yyval.sel), _gmx_sel_init_method((yyvsp[(2) - (3)].meth), get((yyvsp[(3) - (3)].plist)), (yyvsp[(1) - (3)].str), scanner));
+                 scoped_guard_sfree posmodGuard((yyvsp[-2].str));
+                 set((yyval.sel), _gmx_sel_init_method((yyvsp[-1].meth), get((yyvsp[0].plist)), (yyvsp[-2].str), scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 2275 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 48:
-/* Line 1787 of yacc.c  */
-#line 525 "parser.y"
+#line 527 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '+', scanner));
+                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[-2].sel)), get((yyvsp[0].sel)), '+', scanner));
                  END_ACTION;
              }
+#line 2285 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 49:
-/* Line 1787 of yacc.c  */
-#line 531 "parser.y"
+#line 533 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '-', scanner));
+                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[-2].sel)), get((yyvsp[0].sel)), '-', scanner));
                  END_ACTION;
              }
+#line 2295 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 50:
-/* Line 1787 of yacc.c  */
-#line 537 "parser.y"
+#line 539 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '*', scanner));
+                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[-2].sel)), get((yyvsp[0].sel)), '*', scanner));
                  END_ACTION;
              }
+#line 2305 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 51:
-/* Line 1787 of yacc.c  */
-#line 543 "parser.y"
+#line 545 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '/', scanner));
+                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[-2].sel)), get((yyvsp[0].sel)), '/', scanner));
                  END_ACTION;
              }
+#line 2315 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 52:
-/* Line 1787 of yacc.c  */
-#line 549 "parser.y"
+#line 551 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(2) - (2)].sel)), SelectionTreeElementPointer(), '-', scanner));
+                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[0].sel)), SelectionTreeElementPointer(), '-', scanner));
                  END_ACTION;
              }
+#line 2325 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 53:
-/* Line 1787 of yacc.c  */
-#line 555 "parser.y"
+#line 557 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '^', scanner));
+                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[-2].sel)), get((yyvsp[0].sel)), '^', scanner));
                  END_ACTION;
              }
+#line 2335 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 54:
-/* Line 1787 of yacc.c  */
-#line 560 "parser.y"
-    { (yyval.sel) = (yyvsp[(2) - (3)].sel); }
+#line 562 "parser.y" /* yacc.c:1646  */
+    { (yyval.sel) = (yyvsp[-1].sel); }
+#line 2341 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 55:
-/* Line 1787 of yacc.c  */
-#line 568 "parser.y"
+#line 570 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer sel(
                         new SelectionTreeElement(SEL_CONST, (yyloc)));
                  _gmx_selelem_set_vtype(sel, STR_VALUE);
                  _gmx_selvalue_reserve(&sel->v, 1);
-                 sel->v.u.s[0] = (yyvsp[(1) - (1)].str);
+                 sel->v.u.s[0] = (yyvsp[0].str);
                  set((yyval.sel), sel);
                  END_ACTION;
              }
+#line 2356 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 56:
-/* Line 1787 of yacc.c  */
-#line 579 "parser.y"
+#line 581 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree posmodGuard((yyvsp[(1) - (2)].str));
-                 set((yyval.sel), _gmx_sel_init_keyword((yyvsp[(2) - (2)].meth), SelectionParserValueListPointer(), (yyvsp[(1) - (2)].str), scanner));
+                 scoped_guard_sfree posmodGuard((yyvsp[-1].str));
+                 set((yyval.sel), _gmx_sel_init_keyword((yyvsp[0].meth), SelectionParserValueListPointer(), (yyvsp[-1].str), scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 2368 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 57:
-/* Line 1787 of yacc.c  */
-#line 594 "parser.y"
+#line 596 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_const_position((yyvsp[(2) - (7)].r), (yyvsp[(4) - (7)].r), (yyvsp[(6) - (7)].r), scanner));
+                 set((yyval.sel), _gmx_sel_init_const_position((yyvsp[-5].r), (yyvsp[-3].r), (yyvsp[-1].r), scanner));
                  END_ACTION;
              }
+#line 2378 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 58:
-/* Line 1787 of yacc.c  */
-#line 602 "parser.y"
-    { (yyval.sel) = (yyvsp[(2) - (3)].sel); }
+#line 604 "parser.y" /* yacc.c:1646  */
+    { (yyval.sel) = (yyvsp[-1].sel); }
+#line 2384 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 59:
-/* Line 1787 of yacc.c  */
-#line 607 "parser.y"
+#line 609 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_method((yyvsp[(1) - (2)].meth), get((yyvsp[(2) - (2)].plist)), NULL, scanner));
+                 set((yyval.sel), _gmx_sel_init_method((yyvsp[-1].meth), get((yyvsp[0].plist)), NULL, scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 2395 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 60:
-/* Line 1787 of yacc.c  */
-#line 617 "parser.y"
+#line 619 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree keywordGuard((yyvsp[(1) - (3)].str));
-                 set((yyval.sel), _gmx_sel_init_position(get((yyvsp[(3) - (3)].sel)), (yyvsp[(1) - (3)].str), scanner));
+                 scoped_guard_sfree keywordGuard((yyvsp[-2].str));
+                 set((yyval.sel), _gmx_sel_init_position(get((yyvsp[0].sel)), (yyvsp[-2].str), scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 2407 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 61:
-/* Line 1787 of yacc.c  */
-#line 631 "parser.y"
+#line 633 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[(1) - (1)].sel)), scanner));
+                 set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[0].sel)), scanner));
                  END_ACTION;
              }
+#line 2417 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 62:
-/* Line 1787 of yacc.c  */
-#line 639 "parser.y"
+#line 641 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[(1) - (1)].sel)), scanner));
+                 set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[0].sel)), scanner));
                  END_ACTION;
              }
+#line 2427 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 63:
-/* Line 1787 of yacc.c  */
-#line 647 "parser.y"
+#line 649 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[(1) - (1)].sel)), scanner));
+                 set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[0].sel)), scanner));
                  END_ACTION;
              }
+#line 2437 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 64:
-/* Line 1787 of yacc.c  */
-#line 660 "parser.y"
-    { (yyval.plist) = (yyvsp[(1) - (1)].plist); }
+#line 662 "parser.y" /* yacc.c:1646  */
+    { (yyval.plist) = (yyvsp[0].plist); }
+#line 2443 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 65:
-/* Line 1787 of yacc.c  */
-#line 662 "parser.y"
-    { (yyval.plist) = (yyvsp[(1) - (2)].plist); }
+#line 664 "parser.y" /* yacc.c:1646  */
+    { (yyval.plist) = (yyvsp[-1].plist); }
+#line 2449 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 66:
-/* Line 1787 of yacc.c  */
-#line 667 "parser.y"
+#line 669 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
                  set((yyval.plist), SelectionParserParameter::createList());
                  END_ACTION;
              }
+#line 2459 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 67:
-/* Line 1787 of yacc.c  */
-#line 673 "parser.y"
+#line 675 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 SelectionParserParameterListPointer list(get((yyvsp[(1) - (2)].plist)));
-                 list->push_back(get((yyvsp[(2) - (2)].param)));
+                 SelectionParserParameterListPointer list(get((yyvsp[-1].plist)));
+                 list->push_back(get((yyvsp[0].param)));
                  set((yyval.plist), std::move(list));
                  END_ACTION;
              }
+#line 2471 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 68:
-/* Line 1787 of yacc.c  */
-#line 684 "parser.y"
+#line 686 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree nameGuard((yyvsp[(1) - (2)].str));
-                 set((yyval.param), SelectionParserParameter::create((yyvsp[(1) - (2)].str), get((yyvsp[(2) - (2)].vlist)), (yyloc)));
+                 scoped_guard_sfree nameGuard((yyvsp[-1].str));
+                 set((yyval.param), SelectionParserParameter::create((yyvsp[-1].str), get((yyvsp[0].vlist)), (yyloc)));
                  END_ACTION;
              }
+#line 2482 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 69:
-/* Line 1787 of yacc.c  */
-#line 692 "parser.y"
-    { (yyval.vlist) = (yyvsp[(1) - (1)].vlist);   }
+#line 694 "parser.y" /* yacc.c:1646  */
+    { (yyval.vlist) = (yyvsp[0].vlist);   }
+#line 2488 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 70:
-/* Line 1787 of yacc.c  */
-#line 693 "parser.y"
-    { (yyval.vlist) = (yyvsp[(2) - (3)].vlist);   }
+#line 695 "parser.y" /* yacc.c:1646  */
+    { (yyval.vlist) = (yyvsp[-1].vlist);   }
+#line 2494 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 71:
-/* Line 1787 of yacc.c  */
-#line 698 "parser.y"
+#line 700 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
                  set((yyval.vlist), SelectionParserValue::createList());
                  END_ACTION;
              }
+#line 2504 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 72:
-/* Line 1787 of yacc.c  */
-#line 704 "parser.y"
+#line 706 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 SelectionParserValueListPointer list(get((yyvsp[(1) - (2)].vlist)));
-                 list->push_back(get((yyvsp[(2) - (2)].val)));
+                 SelectionParserValueListPointer list(get((yyvsp[-1].vlist)));
+                 list->push_back(get((yyvsp[0].val)));
                  set((yyval.vlist), std::move(list));
                  END_ACTION;
              }
+#line 2516 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 73:
-/* Line 1787 of yacc.c  */
-#line 712 "parser.y"
+#line 714 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 SelectionParserValueListPointer list(get((yyvsp[(1) - (3)].vlist)));
-                 list->push_back(get((yyvsp[(3) - (3)].val)));
+                 SelectionParserValueListPointer list(get((yyvsp[-2].vlist)));
+                 list->push_back(get((yyvsp[0].val)));
                  set((yyval.vlist), std::move(list));
                  END_ACTION;
              }
+#line 2528 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 74:
-/* Line 1787 of yacc.c  */
-#line 722 "parser.y"
-    { (yyval.vlist) = (yyvsp[(1) - (1)].vlist); }
+#line 724 "parser.y" /* yacc.c:1646  */
+    { (yyval.vlist) = (yyvsp[0].vlist); }
+#line 2534 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 75:
-/* Line 1787 of yacc.c  */
-#line 723 "parser.y"
-    { (yyval.vlist) = (yyvsp[(2) - (3)].vlist); }
+#line 725 "parser.y" /* yacc.c:1646  */
+    { (yyval.vlist) = (yyvsp[-1].vlist); }
+#line 2540 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 76:
-/* Line 1787 of yacc.c  */
-#line 728 "parser.y"
+#line 730 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.vlist), SelectionParserValue::createList(get((yyvsp[(1) - (1)].val))));
+                 set((yyval.vlist), SelectionParserValue::createList(get((yyvsp[0].val))));
                  END_ACTION;
              }
+#line 2550 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 77:
-/* Line 1787 of yacc.c  */
-#line 734 "parser.y"
+#line 736 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 SelectionParserValueListPointer list(get((yyvsp[(1) - (2)].vlist)));
-                 list->push_back(get((yyvsp[(2) - (2)].val)));
+                 SelectionParserValueListPointer list(get((yyvsp[-1].vlist)));
+                 list->push_back(get((yyvsp[0].val)));
                  set((yyval.vlist), std::move(list));
                  END_ACTION;
              }
+#line 2562 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 78:
-/* Line 1787 of yacc.c  */
-#line 742 "parser.y"
+#line 744 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 SelectionParserValueListPointer list(get((yyvsp[(1) - (3)].vlist)));
-                 list->push_back(get((yyvsp[(3) - (3)].val)));
+                 SelectionParserValueListPointer list(get((yyvsp[-2].vlist)));
+                 list->push_back(get((yyvsp[0].val)));
                  set((yyval.vlist), std::move(list));
                  END_ACTION;
              }
+#line 2574 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 79:
-/* Line 1787 of yacc.c  */
-#line 752 "parser.y"
+#line 754 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[(1) - (1)].sel))));
+                 set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[0].sel))));
                  END_ACTION;
              }
+#line 2584 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 80:
-/* Line 1787 of yacc.c  */
-#line 758 "parser.y"
+#line 760 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[(1) - (1)].sel))));
+                 set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[0].sel))));
                  END_ACTION;
              }
+#line 2594 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 81:
-/* Line 1787 of yacc.c  */
-#line 764 "parser.y"
+#line 766 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[(1) - (1)].sel))));
+                 set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[0].sel))));
                  END_ACTION;
              }
+#line 2604 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 82:
-/* Line 1787 of yacc.c  */
-#line 770 "parser.y"
+#line 772 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[(1) - (1)].sel))));
+                 set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[0].sel))));
                  END_ACTION;
              }
+#line 2614 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 83:
-/* Line 1787 of yacc.c  */
-#line 775 "parser.y"
-    { (yyval.val) = (yyvsp[(1) - (1)].val); }
+#line 777 "parser.y" /* yacc.c:1646  */
+    { (yyval.val) = (yyvsp[0].val); }
+#line 2620 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 84:
-/* Line 1787 of yacc.c  */
-#line 780 "parser.y"
+#line 782 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.val), SelectionParserValue::createInteger((yyvsp[(1) - (1)].i), (yyloc)));
+                 set((yyval.val), SelectionParserValue::createInteger((yyvsp[0].i), (yyloc)));
                  END_ACTION;
              }
+#line 2630 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 85:
-/* Line 1787 of yacc.c  */
-#line 786 "parser.y"
+#line 788 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.val), SelectionParserValue::createReal((yyvsp[(1) - (1)].r), (yyloc)));
+                 set((yyval.val), SelectionParserValue::createReal((yyvsp[0].r), (yyloc)));
                  END_ACTION;
              }
+#line 2640 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 86:
-/* Line 1787 of yacc.c  */
-#line 792 "parser.y"
+#line 794 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree stringGuard((yyvsp[(1) - (1)].str));
-                 set((yyval.val), SelectionParserValue::createString((yyvsp[(1) - (1)].str), (yyloc)));
+                 scoped_guard_sfree stringGuard((yyvsp[0].str));
+                 set((yyval.val), SelectionParserValue::createString((yyvsp[0].str), (yyloc)));
                  END_ACTION;
              }
+#line 2651 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 87:
-/* Line 1787 of yacc.c  */
-#line 798 "parser.y"
-    { (yyval.val) = (yyvsp[(1) - (1)].val); }
+#line 800 "parser.y" /* yacc.c:1646  */
+    { (yyval.val) = (yyvsp[0].val); }
+#line 2657 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 88:
-/* Line 1787 of yacc.c  */
-#line 803 "parser.y"
+#line 805 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.val), SelectionParserValue::createIntegerRange((yyvsp[(1) - (3)].i), (yyvsp[(3) - (3)].i), (yyloc)));
+                 set((yyval.val), SelectionParserValue::createIntegerRange((yyvsp[-2].i), (yyvsp[0].i), (yyloc)));
                  END_ACTION;
              }
+#line 2667 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 89:
-/* Line 1787 of yacc.c  */
-#line 809 "parser.y"
+#line 811 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.val), SelectionParserValue::createRealRange((yyvsp[(1) - (3)].i), (yyvsp[(3) - (3)].r), (yyloc)));
+                 set((yyval.val), SelectionParserValue::createRealRange((yyvsp[-2].i), (yyvsp[0].r), (yyloc)));
                  END_ACTION;
              }
+#line 2677 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 90:
-/* Line 1787 of yacc.c  */
-#line 815 "parser.y"
+#line 817 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.val), SelectionParserValue::createRealRange((yyvsp[(1) - (3)].r), (yyvsp[(3) - (3)].r), (yyloc)));
+                 set((yyval.val), SelectionParserValue::createRealRange((yyvsp[-2].r), (yyvsp[0].r), (yyloc)));
                  END_ACTION;
              }
+#line 2687 "parser.cpp" /* yacc.c:1646  */
     break;
 
 
-/* Line 1787 of yacc.c  */
-#line 2917 "parser.cpp"
+#line 2691 "parser.cpp" /* yacc.c:1646  */
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
@@ -2936,7 +2710,7 @@ yyreduce:
   *++yyvsp = yyval;
   *++yylsp = yyloc;
 
-  /* Now `shift' the result of the reduction.  Determine what state
+  /* Now 'shift' the result of the reduction.  Determine what state
      that goes to, based on the state we popped back to and the rule
      number reduced by.  */
 
@@ -2951,9 +2725,9 @@ yyreduce:
   goto yynewstate;
 
 
-/*------------------------------------.
-| yyerrlab -- here on detecting error |
-`------------------------------------*/
+/*--------------------------------------.
+| yyerrlab -- here on detecting error |
+`--------------------------------------*/
 yyerrlab:
   /* Make sure we have latest lookahead translation.  See comments at
      user semantic actions for why this is necessary.  */
@@ -3004,20 +2778,20 @@ yyerrlab:
   if (yyerrstatus == 3)
     {
       /* If just tried and failed to reuse lookahead token after an
-        error, discard it.  */
+         error, discard it.  */
 
       if (yychar <= YYEOF)
-       {
-         /* Return failure if at end of input.  */
-         if (yychar == YYEOF)
-           YYABORT;
-       }
+        {
+          /* Return failure if at end of input.  */
+          if (yychar == YYEOF)
+            YYABORT;
+        }
       else
-       {
-         yydestruct ("Error: discarding",
-                     yytoken, &yylval, &yylloc, scanner);
-         yychar = YYEMPTY;
-       }
+        {
+          yydestruct ("Error: discarding",
+                      yytoken, &yylval, &yylloc, scanner);
+          yychar = YYEMPTY;
+        }
     }
 
   /* Else will try to reuse lookahead token after shifting the error
@@ -3037,7 +2811,7 @@ yyerrorlab:
      goto yyerrorlab;
 
   yyerror_range[1] = yylsp[1-yylen];
-  /* Do not reclaim the symbols of the rule which action triggered
+  /* Do not reclaim the symbols of the rule whose action triggered
      this YYERROR.  */
   YYPOPSTACK (yylen);
   yylen = 0;
@@ -3050,29 +2824,29 @@ yyerrorlab:
 | yyerrlab1 -- common code for both syntax error and YYERROR.  |
 `-------------------------------------------------------------*/
 yyerrlab1:
-  yyerrstatus = 3;     /* Each real token shifted decrements this.  */
+  yyerrstatus = 3;      /* Each real token shifted decrements this.  */
 
   for (;;)
     {
       yyn = yypact[yystate];
       if (!yypact_value_is_default (yyn))
-       {
-         yyn += YYTERROR;
-         if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
-           {
-             yyn = yytable[yyn];
-             if (0 < yyn)
-               break;
-           }
-       }
+        {
+          yyn += YYTERROR;
+          if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+            {
+              yyn = yytable[yyn];
+              if (0 < yyn)
+                break;
+            }
+        }
 
       /* Pop the current state because it cannot handle the error token.  */
       if (yyssp == yyss)
-       YYABORT;
+        YYABORT;
 
       yyerror_range[1] = *yylsp;
       yydestruct ("Error: popping",
-                 yystos[yystate], yyvsp, yylsp, scanner);
+                  yystos[yystate], yyvsp, yylsp, scanner);
       YYPOPSTACK (1);
       yystate = *yyssp;
       YY_STACK_PRINT (yyss, yyssp);
@@ -3128,14 +2902,14 @@ yyreturn:
       yydestruct ("Cleanup: discarding lookahead",
                   yytoken, &yylval, &yylloc, scanner);
     }
-  /* Do not reclaim the symbols of the rule which action triggered
+  /* Do not reclaim the symbols of the rule whose action triggered
      this YYABORT or YYACCEPT.  */
   YYPOPSTACK (yylen);
   YY_STACK_PRINT (yyss, yyssp);
   while (yyssp != yyss)
     {
       yydestruct ("Cleanup: popping",
-                 yystos[*yyssp], yyvsp, yylsp, scanner);
+                  yystos[*yyssp], yyvsp, yylsp, scanner);
       YYPOPSTACK (1);
     }
 #ifndef yyoverflow
@@ -3149,8 +2923,5 @@ yypushreturn:
   if (yymsg != yymsgbuf)
     YYSTACK_FREE (yymsg);
 #endif
-  /* Make sure YYID is used.  */
-  return YYID (yyresult);
+  return yyresult;
 }
-
-
index 2e9a7611ee168993a43bbdfe37a5103cba1c700a..a0263cee49ccd82604ea1b7e7ea1fb3ef104ff16 100644 (file)
@@ -1,19 +1,19 @@
-/* A Bison parser, made by GNU Bison 2.7.12-4996.  */
+/* A Bison parser, made by GNU Bison 3.0.4.  */
 
 /* Bison interface for Yacc-like parsers in C
-   
-      Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
-   
+
+   Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
+
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
-   
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
    special exception, which will cause the skeleton and the resulting
    Bison output files to be licensed under the GNU General Public
    License without this special exception.
-   
+
    This special exception was added by the Free Software Foundation in
    version 2.2 of Bison.  */
 
 #ifndef YY__GMX_SEL_YY_PARSER_H_INCLUDED
 # define YY__GMX_SEL_YY_PARSER_H_INCLUDED
-/* Enabling traces.  */
+/* Debug traces.  */
 #ifndef YYDEBUG
 # define YYDEBUG 1
 #endif
 extern int _gmx_sel_yydebug;
 #endif
 /* "%code requires" blocks.  */
-/* Line 2053 of yacc.c  */
-#line 1 "parser.y"
+#line 1 "parser.y" /* yacc.c:1909  */
 
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -77,65 +76,60 @@ extern int _gmx_sel_yydebug;
  * To help us fund GROMACS development, we humbly ask that you cite
  * the research papers on the package. Check out http://www.gromacs.org.
  */
-
-/* Line 2053 of yacc.c  */
-#line 76 "parser.y"
+#line 76 "parser.y" /* yacc.c:1909  */
 
 #include "parsetree.h"
 #include "selelem.h"
 
 #define YYLTYPE ::gmx::SelectionLocation
 
+#line 87 "parser.h" /* yacc.c:1909  */
 
-/* Line 2053 of yacc.c  */
-#line 92 "parser.h"
-
-/* Tokens.  */
+/* Token type.  */
 #ifndef YYTOKENTYPE
 # define YYTOKENTYPE
-   /* Put the tokens into the symbol table, so that GDB and other debuggers
-      know about them.  */
-   enum yytokentype {
-     INVALID = 258,
-     TOK_INT = 259,
-     TOK_REAL = 260,
-     STR = 261,
-     IDENTIFIER = 262,
-     CMD_SEP = 263,
-     GROUP = 264,
-     TO = 265,
-     VARIABLE_NUMERIC = 266,
-     VARIABLE_GROUP = 267,
-     VARIABLE_POS = 268,
-     KEYWORD_NUMERIC = 269,
-     KEYWORD_STR = 270,
-     KEYWORD_POS = 271,
-     KEYWORD_GROUP = 272,
-     METHOD_NUMERIC = 273,
-     METHOD_GROUP = 274,
-     METHOD_POS = 275,
-     MODIFIER = 276,
-     EMPTY_POSMOD = 277,
-     PARAM = 278,
-     END_OF_METHOD = 279,
-     OF = 280,
-     CMP_OP = 281,
-     PARAM_REDUCT = 282,
-     XOR = 283,
-     OR = 284,
-     AND = 285,
-     NOT = 286,
-     UNARY_NEG = 287,
-     NUM_REDUCT = 288
-   };
+  enum yytokentype
+  {
+    INVALID = 258,
+    TOK_INT = 259,
+    TOK_REAL = 260,
+    STR = 261,
+    IDENTIFIER = 262,
+    CMD_SEP = 263,
+    GROUP = 264,
+    TO = 265,
+    VARIABLE_NUMERIC = 266,
+    VARIABLE_GROUP = 267,
+    VARIABLE_POS = 268,
+    KEYWORD_NUMERIC = 269,
+    KEYWORD_STR = 270,
+    KEYWORD_POS = 271,
+    KEYWORD_GROUP = 272,
+    METHOD_NUMERIC = 273,
+    METHOD_GROUP = 274,
+    METHOD_POS = 275,
+    MODIFIER = 276,
+    EMPTY_POSMOD = 277,
+    PARAM = 278,
+    END_OF_METHOD = 279,
+    OF = 280,
+    CMP_OP = 281,
+    PARAM_REDUCT = 282,
+    OR = 283,
+    XOR = 284,
+    AND = 285,
+    NOT = 286,
+    UNARY_NEG = 287,
+    NUM_REDUCT = 288
+  };
 #endif
 
-
+/* Value type.  */
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
+
+union YYSTYPE
 {
-/* Line 2053 of yacc.c  */
-#line 83 "parser.y"
+#line 83 "parser.y" /* yacc.c:1909  */
 
     int                         i;
     real                        r;
@@ -150,29 +144,30 @@ typedef union YYSTYPE
     gmx::SelectionParserParameter               *param;
     gmx::SelectionParserParameterListPointer    *plist;
 
+#line 148 "parser.h" /* yacc.c:1909  */
+};
 
-/* Line 2053 of yacc.c  */
-#line 156 "parser.h"
-} YYSTYPE;
+typedef union YYSTYPE YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
 #endif
 
+/* Location type.  */
 #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
-typedef struct YYLTYPE
+typedef struct YYLTYPE YYLTYPE;
+struct YYLTYPE
 {
   int first_line;
   int first_column;
   int last_line;
   int last_column;
-} YYLTYPE;
-# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
+};
 # define YYLTYPE_IS_DECLARED 1
 # define YYLTYPE_IS_TRIVIAL 1
 #endif
 
 
+
 #ifndef YYPUSH_MORE_DEFINED
 # define YYPUSH_MORE_DEFINED
 enum { YYPUSH_MORE = 4 };
@@ -180,21 +175,9 @@ enum { YYPUSH_MORE = 4 };
 
 typedef struct _gmx_sel_yypstate _gmx_sel_yypstate;
 
-#if defined __STDC__ || defined __cplusplus
 int _gmx_sel_yypush_parse (_gmx_sel_yypstate *ps, int pushed_char, YYSTYPE const *pushed_val, YYLTYPE *pushed_loc, void *scanner);
-#else
-int _gmx_sel_yypush_parse ();
-#endif
 
-#if defined __STDC__ || defined __cplusplus
 _gmx_sel_yypstate * _gmx_sel_yypstate_new (void);
-#else
-_gmx_sel_yypstate * _gmx_sel_yypstate_new ();
-#endif
-#if defined __STDC__ || defined __cplusplus
 void _gmx_sel_yypstate_delete (_gmx_sel_yypstate *ps);
-#else
-void _gmx_sel_yypstate_delete ();
-#endif
 
 #endif /* !YY__GMX_SEL_YY_PARSER_H_INCLUDED  */
index de16101d2ba39ccbf28d0b1fb6db1ace6bf69c18..aa57eb089df2a6a4dd9188a6ae1f0a40f182ee60 100644 (file)
@@ -1,20 +1,20 @@
 --- parser.cpp 2014-11-03 06:56:28.000000000 +0200
 +++ parser.cpp 2014-11-03 06:57:35.000000000 +0200
-@@ -470,7 +470,7 @@
+@@ -437,7 +437,7 @@
  
  
  #if (! defined yyoverflow \
 -     && (! defined __cplusplus \
 +     && (! defined __cplusplus || defined GMX_YYFORCE_C_STACK_EXTENSION \
-        || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
-            && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+          || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
+              && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
  
-@@ -1076,7 +1076,7 @@
-     void *scanner;
- #endif
+@@ -955,7 +955,7 @@
+ static void
+ yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, void *scanner)
  {
 -  FILE *yyo = yyoutput;
 +  FILE *yyo gmx_unused = yyoutput;
    YYUSE (yyo);
-   if (!yyvaluep)
-     return;
+   YYUSE (yylocationp);
+   YYUSE (scanner);
index 3cae4446e4b871ea13e06845dd0b4a70418d85eb..c5b989885f0c1b35fa524408deaf600914c65aa0 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -189,7 +189,7 @@ using gmx::SelectionTreeElementPointer;
 %define api.push-pull push
 %locations
 
-%name-prefix="_gmx_sel_yy"
+%name-prefix "_gmx_sel_yy"
 %parse-param { void *scanner }
 
 %%
@@ -205,8 +205,10 @@ commands:    /* empty */
              {
                  BEGIN_ACTION;
                  set($$, _gmx_sel_append_selection(get($2), get($1), scanner));
-                 if (_gmx_sel_parser_should_finish(scanner))
+                 if (_gmx_sel_parser_should_finish(scanner)) {
+                     delete $$;
                      YYACCEPT;
+                 }
                  END_ACTION_TOPLEVEL;
              }
 ;
index dbc1229b900a9712973e60f9a6f3227b09e4257d..68ad13a2ace85fc7857a83d74067b26d77f4034f 100644 (file)
@@ -151,7 +151,7 @@ class PositionCalculationCollection::Impl
          * Can be NULL if none of the calculations require topology data or if
          * setTopology() has not been called.
          */
-        t_topology               *top_;
+        const gmx_mtop_t         *top_;
         //! Pointer to the first data structure.
         gmx_ana_poscalc_t        *first_;
         //! Pointer to the last data structure.
@@ -270,6 +270,29 @@ index_type_for_poscalc(e_poscalc_t type)
 namespace gmx
 {
 
+namespace
+{
+
+//! Helper function for determining required topology information.
+PositionCalculationCollection::RequiredTopologyInfo
+requiredTopologyInfo(e_poscalc_t type, int flags)
+{
+    if (type != POS_ATOM)
+    {
+        if ((flags & POS_MASS) || (flags & POS_FORCES))
+        {
+            return PositionCalculationCollection::RequiredTopologyInfo::TopologyAndMasses;
+        }
+        if (type == POS_RES || type == POS_MOL)
+        {
+            return PositionCalculationCollection::RequiredTopologyInfo::Topology;
+        }
+    }
+    return PositionCalculationCollection::RequiredTopologyInfo::None;
+}
+
+}   // namespace
+
 // static
 void
 PositionCalculationCollection::typeFromEnum(const char *post,
@@ -332,6 +355,17 @@ PositionCalculationCollection::typeFromEnum(const char *post,
     }
 }
 
+// static
+PositionCalculationCollection::RequiredTopologyInfo
+PositionCalculationCollection::requiredTopologyInfoForType(const char *post,
+                                                           bool        forces)
+{
+    e_poscalc_t  type;
+    int          flags = (forces ? POS_FORCES : 0);
+    PositionCalculationCollection::typeFromEnum(post, &type, &flags);
+    return requiredTopologyInfo(type, flags);
+}
+
 /********************************************************************
  * PositionCalculationCollection::Impl
  */
@@ -437,7 +471,7 @@ PositionCalculationCollection::~PositionCalculationCollection()
 }
 
 void
-PositionCalculationCollection::setTopology(t_topology *top)
+PositionCalculationCollection::setTopology(const gmx_mtop_t *top)
 {
     impl_->top_ = top;
 }
@@ -702,7 +736,7 @@ void PositionCalculationCollection::initFrame(const t_trxframe *fr)
 static void
 set_poscalc_maxindex(gmx_ana_poscalc_t *pc, gmx_ana_index_t *g, bool bBase)
 {
-    t_topology *top = pc->coll->top_;
+    const gmx_mtop_t *top = pc->coll->top_;
     gmx_ana_index_make_block(&pc->b, top, g, pc->itype, pc->flags & POS_COMPLWHOLE);
     /* Set the type to POS_ATOM if the calculation in fact is such. */
     if (pc->b.nr == pc->b.nra)
@@ -1161,20 +1195,10 @@ gmx_ana_poscalc_free(gmx_ana_poscalc_t *pc)
     sfree(pc);
 }
 
-/*!
- * \param[in] pc  Position calculation data to query.
- * \returns   true if \p pc requires topology for initialization and/or
- *   evaluation, false otherwise.
- */
-bool
-gmx_ana_poscalc_requires_top(gmx_ana_poscalc_t *pc)
+gmx::PositionCalculationCollection::RequiredTopologyInfo
+gmx_ana_poscalc_required_topology_info(gmx_ana_poscalc_t *pc)
 {
-    if ((pc->flags & POS_MASS) || pc->type == POS_RES || pc->type == POS_MOL
-        || ((pc->flags & POS_FORCES) && pc->type != POS_ATOM))
-    {
-        return true;
-    }
-    return false;
+    return gmx::requiredTopologyInfo(pc->type, pc->flags);
 }
 
 /*!
@@ -1190,7 +1214,7 @@ gmx_ana_poscalc_requires_top(gmx_ana_poscalc_t *pc)
  */
 void
 gmx_ana_poscalc_update(gmx_ana_poscalc_t *pc, gmx_ana_pos_t *p,
-                       gmx_ana_index_t *g, t_trxframe *fr, t_pbc *pbc)
+                       gmx_ana_index_t *g, t_trxframe *fr, const t_pbc *pbc)
 {
     int  i, bi, bj;
 
@@ -1307,7 +1331,7 @@ gmx_ana_poscalc_update(gmx_ana_poscalc_t *pc, gmx_ana_pos_t *p,
             }
         }
         gmx::ConstArrayRef<int> index = pc->coll->getFrameIndices(pc->b.nra, pc->b.a);
-        const t_topology       *top   = pc->coll->top_;
+        const gmx_mtop_t       *top   = pc->coll->top_;
         const bool              bMass = pc->flags & POS_MASS;
         switch (pc->type)
         {
index eef4f00211e8a81320c48d190ae59d986181b164..e37628dea0fb28efeedde4accbb33cc37152853d 100644 (file)
@@ -131,8 +131,8 @@ struct gmx_ana_poscalc_t;
 
 struct gmx_ana_index_t;
 struct gmx_ana_pos_t;
+struct gmx_mtop_t;
 struct t_pbc;
-struct t_topology;
 struct t_trxframe;
 
 namespace gmx
@@ -178,6 +178,14 @@ namespace gmx
 class PositionCalculationCollection
 {
     public:
+        //! Describes what topology information is needed for position calculation.
+        enum class RequiredTopologyInfo
+        {
+            None,              //!< No topology is needed.
+            Topology,          //!< Topology is needed (residue/molecule info).
+            TopologyAndMasses  //!< Masses are needed.
+        };
+
         /*! \brief
          * Array of strings acceptable for position calculation type enum.
          *
@@ -210,6 +218,15 @@ class PositionCalculationCollection
          * \see typeEnumValues
          */
         static void typeFromEnum(const char *post, e_poscalc_t *type, int *flags);
+        /*! \brief
+         * Returns what information is needed for position evaluation.
+         *
+         * \param[in] post   Position type (see typeFromEnum()).
+         * \param[in] forces Whether forces are needed.
+         * \returns   What topology information is required for initializing
+         *     and/or evaluating the positions.
+         */
+        static RequiredTopologyInfo requiredTopologyInfoForType(const char *post, bool forces);
 
         /*! \brief
          * Creates a new position calculation collection object.
@@ -236,7 +253,7 @@ class PositionCalculationCollection
          *
          * Does not throw.
          */
-        void setTopology(t_topology *top);
+        void setTopology(const gmx_mtop_t *top);
         /*! \brief
          * Prints information about calculations.
          *
@@ -344,14 +361,20 @@ gmx_ana_poscalc_init_pos(gmx_ana_poscalc_t *pc, gmx_ana_pos_t *p);
 /** Frees the memory allocated for position calculation. */
 void
 gmx_ana_poscalc_free(gmx_ana_poscalc_t *pc);
-/** Returns true if the position calculation requires topology information. */
-bool
-gmx_ana_poscalc_requires_top(gmx_ana_poscalc_t *pc);
+/*! \brief
+ * Returns true if the position calculation requires topology information.
+ *
+ * \param[in] pc  Position calculation data to query.
+ * \returns   Which topology information \p pc requires for initialization
+ *     and/or evaluation.
+ */
+gmx::PositionCalculationCollection::RequiredTopologyInfo
+gmx_ana_poscalc_required_topology_info(gmx_ana_poscalc_t *pc);
 
 /** Updates a single COM/COG structure for a frame. */
 void
 gmx_ana_poscalc_update(gmx_ana_poscalc_t *pc,
                        gmx_ana_pos_t *p, gmx_ana_index_t *g,
-                       t_trxframe *fr, t_pbc *pbc);
+                       t_trxframe *fr, const t_pbc *pbc);
 
 #endif
index c16a479a6793abca29797c07e961632832fd5963..0f506f14d4a6481e960c3bdafded2c54fc9fb077 100644 (file)
@@ -569,11 +569,16 @@ static yyconst flex_int16_t yy_chk[151] =
 // when we have return statements followed by break. Instead, we add breaks
 // manually.
 #define YY_BREAK
+
+#ifdef __INTEL_COMPILER
+// Ignore unused variables in generated code.
+#pragma warning(disable:593)
+#endif
 #define YY_NO_UNISTD_H 1
 
 
 
-#line 577 "scanner.cpp"
+#line 582 "scanner.cpp"
 
 #define INITIAL 0
 #define matchof 1
@@ -837,7 +842,7 @@ YY_DECL
                }
 
        {
-#line 99 "scanner.l"
+#line 104 "scanner.l"
 
 
 
@@ -871,7 +876,7 @@ YY_DECL
     }
 
 
-#line 875 "scanner.cpp"
+#line 880 "scanner.cpp"
 
        while ( /*CONSTCOND*/1 )                /* loops until end-of-file is reached */
                {
@@ -926,34 +931,34 @@ do_action:        /* This label is used only to access EOF actions. */
 
 case 1:
 YY_RULE_SETUP
-#line 132 "scanner.l"
+#line 137 "scanner.l"
 break;
        YY_BREAK
 case 2:
 YY_RULE_SETUP
-#line 133 "scanner.l"
+#line 138 "scanner.l"
 { yylval->i   = strtol(yytext, NULL, 10);    ADD_TOKEN; return TOK_INT; }
        YY_BREAK
 case 3:
 YY_RULE_SETUP
-#line 134 "scanner.l"
+#line 139 "scanner.l"
 { yylval->r   = strtod(yytext, NULL);        ADD_TOKEN; return TOK_REAL; }
        YY_BREAK
 case 4:
 YY_RULE_SETUP
-#line 135 "scanner.l"
+#line 140 "scanner.l"
 { yylval->str = gmx_strndup(yytext+1, yyleng-2); ADD_TOKEN; return STR;  }
        YY_BREAK
 case 5:
 /* rule 5 can match eol */
 YY_RULE_SETUP
-#line 137 "scanner.l"
+#line 142 "scanner.l"
 { _gmx_sel_lexer_add_token(yylloc, " ", 1, state); break; }
        YY_BREAK
 case 6:
 /* rule 6 can match eol */
 YY_RULE_SETUP
-#line 138 "scanner.l"
+#line 143 "scanner.l"
 {
                     if (yytext[0] == ';' || state->statusWriter != NULL)
                     {
@@ -969,94 +974,94 @@ YY_RULE_SETUP
                 }
        YY_BREAK
 case YY_STATE_EOF(cmdstart):
-#line 152 "scanner.l"
+#line 157 "scanner.l"
 { state->bCmdStart = true; yyterminate(); }
        YY_BREAK
 case YY_STATE_EOF(INITIAL):
 case YY_STATE_EOF(matchof):
 case YY_STATE_EOF(matchbool):
-#line 153 "scanner.l"
+#line 158 "scanner.l"
 { state->bCmdStart = true; return CMD_SEP; }
        YY_BREAK
 
 case 7:
 YY_RULE_SETUP
-#line 156 "scanner.l"
+#line 161 "scanner.l"
 { ADD_TOKEN; yylval->i = 1; return TOK_INT; }
        YY_BREAK
 case 8:
 YY_RULE_SETUP
-#line 157 "scanner.l"
+#line 162 "scanner.l"
 { ADD_TOKEN; yylval->i = 0; return TOK_INT; }
        YY_BREAK
 
 case 9:
 YY_RULE_SETUP
-#line 159 "scanner.l"
+#line 164 "scanner.l"
 { ADD_TOKEN; return GROUP; }
        YY_BREAK
 case 10:
 YY_RULE_SETUP
-#line 160 "scanner.l"
+#line 165 "scanner.l"
 { ADD_TOKEN; return TO; }
        YY_BREAK
 case 11:
 YY_RULE_SETUP
-#line 161 "scanner.l"
+#line 166 "scanner.l"
 { ADD_TOKEN; BEGIN(0); return OF; }
        YY_BREAK
 case 12:
 YY_RULE_SETUP
-#line 162 "scanner.l"
+#line 167 "scanner.l"
 { ADD_TOKEN; return AND; }
        YY_BREAK
 case 13:
 YY_RULE_SETUP
-#line 163 "scanner.l"
+#line 168 "scanner.l"
 { ADD_TOKEN; return OR; }
        YY_BREAK
 case 14:
 YY_RULE_SETUP
-#line 164 "scanner.l"
+#line 169 "scanner.l"
 { ADD_TOKEN; return XOR; }
        YY_BREAK
 case 15:
 YY_RULE_SETUP
-#line 165 "scanner.l"
+#line 170 "scanner.l"
 { ADD_TOKEN; return NOT; }
        YY_BREAK
 case 16:
 YY_RULE_SETUP
-#line 166 "scanner.l"
+#line 171 "scanner.l"
 { yylval->str = gmx_strndup(yytext, yyleng); ADD_TOKEN; return CMP_OP; }
        YY_BREAK
 case 17:
 YY_RULE_SETUP
-#line 168 "scanner.l"
+#line 173 "scanner.l"
 { return _gmx_sel_lexer_process_identifier(yylval, yylloc, yytext, yyleng, state); }
        YY_BREAK
 case 18:
 /* rule 18 can match eol */
 YY_RULE_SETUP
-#line 170 "scanner.l"
+#line 175 "scanner.l"
 { _gmx_sel_lexer_add_token(yylloc, " ", 1, state); break; }
        YY_BREAK
 case 19:
 YY_RULE_SETUP
-#line 171 "scanner.l"
+#line 176 "scanner.l"
 { yylval->str = gmx_strndup(yytext, yyleng); ADD_TOKEN; return STR; }
        YY_BREAK
 case 20:
 YY_RULE_SETUP
-#line 172 "scanner.l"
+#line 177 "scanner.l"
 { ADD_TOKEN; return yytext[0]; }
        YY_BREAK
 case 21:
 YY_RULE_SETUP
-#line 173 "scanner.l"
+#line 178 "scanner.l"
 YY_FATAL_ERROR( "flex scanner jammed" );
        YY_BREAK
-#line 1060 "scanner.cpp"
+#line 1065 "scanner.cpp"
 
        case YY_END_OF_BUFFER:
                {
@@ -2224,4 +2229,4 @@ void _gmx_sel_yyfree (void * ptr , yyscan_t yyscanner)
 
 #define YYTABLES_NAME "yytables"
 
-#line 173 "scanner.l"
+#line 178 "scanner.l"
index 2c03a33e4278e4bbb7956e6d5524ffabd047f823..105250f2d4711ca117109cb66f6894baff99c0db 100644 (file)
 // when we have return statements followed by break. Instead, we add breaks
 // manually.
 #define YY_BREAK
+
+#ifdef __INTEL_COMPILER
+// Ignore unused variables in generated code.
+#pragma warning(disable:593)
+#endif
 %}
 
 INTEGER    [[:digit:]]+
index 0e23931895812e50d6d941e92514385b5f4a781b..14d3030508e30446a5df94834a9bda7f9531da50 100644 (file)
@@ -357,7 +357,7 @@ extern int _gmx_sel_yylex (yyscan_t yyscanner);
 #undef YY_DECL
 #endif
 
-#line 173 "scanner.l"
+#line 178 "scanner.l"
 
 #line 363 "scanner_flex.h"
 #undef _gmx_sel_yyIN_HEADER
index 0b642b5ba9c66d2d0651d6c500966bb486a2f321..d1ec9e623c3059ad19ff8c885768acf611d43f0e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -47,6 +47,7 @@
 
 #include "gromacs/selection/nbsearch.h"
 #include "gromacs/selection/position.h"
+#include "gromacs/topology/mtop_lookup.h"
 #include "gromacs/topology/topology.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
@@ -160,22 +161,24 @@ namespace
  *
  * Does not throw if enough space has been reserved for the output vectors.
  */
-void computeMassesAndCharges(const t_topology *top, const gmx_ana_pos_t &pos,
+void computeMassesAndCharges(const gmx_mtop_t *top, const gmx_ana_pos_t &pos,
                              std::vector<real> *masses,
                              std::vector<real> *charges)
 {
     GMX_ASSERT(top != NULL, "Should not have been called with NULL topology");
     masses->clear();
     charges->clear();
+    int molb = 0;
     for (int b = 0; b < pos.count(); ++b)
     {
         real mass   = 0.0;
         real charge = 0.0;
         for (int i = pos.m.mapb.index[b]; i < pos.m.mapb.index[b+1]; ++i)
         {
-            const int index = pos.m.mapb.a[i];
-            mass   += top->atoms.atom[index].m;
-            charge += top->atoms.atom[index].q;
+            const int     index  = pos.m.mapb.a[i];
+            const t_atom &atom   = mtopGetAtomParameters(top, index, &molb);
+            mass                += atom.m;
+            charge              += atom.q;
         }
         masses->push_back(mass);
         charges->push_back(charge);
@@ -200,7 +203,7 @@ SelectionData::refreshName()
 }
 
 void
-SelectionData::initializeMassesAndCharges(const t_topology *top)
+SelectionData::initializeMassesAndCharges(const gmx_mtop_t *top)
 {
     GMX_ASSERT(posMass_.empty() && posCharge_.empty(),
                "Should not be called more than once");
@@ -219,7 +222,7 @@ SelectionData::initializeMassesAndCharges(const t_topology *top)
 
 
 void
-SelectionData::refreshMassesAndCharges(const t_topology *top)
+SelectionData::refreshMassesAndCharges(const gmx_mtop_t *top)
 {
     if (top != NULL && isDynamic() && !hasFlag(efSelection_DynamicMask))
     {
@@ -251,7 +254,7 @@ SelectionData::computeAverageCoveredFraction(int nframes)
 
 
 void
-SelectionData::restoreOriginalPositions(const t_topology *top)
+SelectionData::restoreOriginalPositions(const gmx_mtop_t *top)
 {
     if (isDynamic())
     {
@@ -289,7 +292,7 @@ Selection::setOriginalId(int i, int id)
 
 
 int
-Selection::initOriginalIdsToGroup(t_topology *top, e_index_t type)
+Selection::initOriginalIdsToGroup(const gmx_mtop_t *top, e_index_t type)
 {
     try
     {
index 47d8a40e45abdbe952ab982690c64653fa78b1a9..1b9df4157d7181f2b581dccd17a5b9972d6a7e1e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -52,7 +52,7 @@
 #include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/gmxassert.h"
 
-struct t_topology;
+struct gmx_mtop_t;
 
 namespace gmx
 {
@@ -150,7 +150,7 @@ class SelectionData
          *
          * Strong exception safety guarantee.
          */
-        void initializeMassesAndCharges(const t_topology *top);
+        void initializeMassesAndCharges(const gmx_mtop_t *top);
         /*! \brief
          * Updates masses and charges after dynamic selection has been
          * evaluated.
@@ -159,7 +159,7 @@ class SelectionData
          *
          * Called by SelectionEvaluator.
          */
-        void refreshMassesAndCharges(const t_topology *top);
+        void refreshMassesAndCharges(const gmx_mtop_t *top);
         /*! \brief
          * Updates the covered fraction after a selection has been evaluated.
          *
@@ -185,7 +185,7 @@ class SelectionData
          * \a rootElement_ object.
          * Called by SelectionEvaluator::evaluateFinal().
          */
-        void restoreOriginalPositions(const t_topology *top);
+        void restoreOriginalPositions(const gmx_mtop_t *top);
 
     private:
         //! Name of the selection.
@@ -532,7 +532,7 @@ class Selection
          * \see setOriginalId()
          * \see SelectionPosition::mappedId()
          */
-        int initOriginalIdsToGroup(t_topology *top, e_index_t type);
+        int initOriginalIdsToGroup(const gmx_mtop_t *top, e_index_t type);
 
         /*! \brief
          * Prints out one-line description of the selection.
index b3280bfedc09a4f16066cc08fc9075c452b8c7c0..56d62fc327ca7e8be7112e6b14194bac8582df9a 100644 (file)
@@ -57,9 +57,9 @@
 #include "poscalc.h"
 #include "selelem.h"
 
+struct gmx_mtop_t;
 struct gmx_sel_mempool_t;
 struct t_pbc;
-struct t_topology;
 struct t_trxframe;
 
 namespace gmx
@@ -71,6 +71,7 @@ typedef std::unique_ptr<internal::SelectionData> SelectionDataPointer;
 typedef std::vector<SelectionDataPointer> SelectionDataList;
 
 class SelectionParserSymbolTable;
+struct SelectionTopologyProperties;
 
 } // namespace gmx
 
@@ -99,7 +100,7 @@ struct gmx_ana_selcollection_t
     char                         **varstrs;
 
     /** Topology for the collection. */
-    t_topology                                        *top;
+    const gmx_mtop_t                                  *top;
     /** Index group that contains all the atoms. */
     gmx_ana_index_t                                    gall;
     /** Memory pool used for selection evaluation. */
@@ -154,6 +155,15 @@ class SelectionCollection::Impl
         void resolveExternalGroups(const gmx::SelectionTreeElementPointer &root,
                                    ExceptionInitializer                   *errors);
 
+        //! Whether forces have been requested for some selection.
+        bool areForcesRequested() const;
+        /*! \brief
+         * Returns topology properties needed for a certain position type.
+         */
+        SelectionTopologyProperties
+        requiredTopologyPropertiesForPositionType(const std::string &post,
+                                                  bool               forces) const;
+
         //! Internal data, used for interfacing with old C code.
         gmx_ana_selcollection_t sc_;
         //! Default reference position type for selections.
index 23fb458901e7c4db871a8d9ab67d5dde92a943c2..ccb1e98dd3962445decc4480ca7c8fd6870b35e4 100644 (file)
@@ -56,6 +56,7 @@
 #include "gromacs/options/ioptionscontainer.h"
 #include "gromacs/selection/selection.h"
 #include "gromacs/selection/selhelp.h"
+#include "gromacs/topology/mtop_util.h"
 #include "gromacs/topology/topology.h"
 #include "gromacs/trajectory/trajectoryframe.h"
 #include "gromacs/utility/exceptions.h"
@@ -406,7 +407,7 @@ early_termination:
     result.reserve(nr);
     for (i = sc->sel.begin() + oldCount; i != sc->sel.end(); ++i)
     {
-        result.push_back(Selection(i->get()));
+        result.emplace_back(i->get());
     }
     return result;
 }
@@ -449,6 +450,24 @@ void checkExternalGroups(const SelectionTreeElementPointer &root,
     }
 }
 
+//! Checks whether the given topology properties are available.
+void checkTopologyProperties(const gmx_mtop_t                  *top,
+                             const SelectionTopologyProperties &props)
+{
+    if (top == NULL)
+    {
+        if (props.hasAny())
+        {
+            GMX_THROW(InconsistentInputError("Selection requires topology information, but none provided"));
+        }
+        return;
+    }
+    if (props.needsMasses && !gmx_mtop_has_masses(top))
+    {
+        GMX_THROW(InconsistentInputError("Selection requires mass information, but it is not available in the topology"));
+    }
+}
+
 }   // namespace
 
 
@@ -479,6 +498,42 @@ void SelectionCollection::Impl::resolveExternalGroups(
 }
 
 
+bool SelectionCollection::Impl::areForcesRequested() const
+{
+    for (const auto &sel : sc_.sel)
+    {
+        if (sel->hasFlag(gmx::efSelection_EvaluateForces))
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+
+SelectionTopologyProperties
+SelectionCollection::Impl::requiredTopologyPropertiesForPositionType(
+        const std::string &post, bool forces) const
+{
+    SelectionTopologyProperties props;
+    if (!post.empty())
+    {
+        switch (PositionCalculationCollection::requiredTopologyInfoForType(post.c_str(), forces))
+        {
+            case PositionCalculationCollection::RequiredTopologyInfo::None:
+                break;
+            case PositionCalculationCollection::RequiredTopologyInfo::Topology:
+                props.merge(SelectionTopologyProperties::topology());
+                break;
+            case PositionCalculationCollection::RequiredTopologyInfo::TopologyAndMasses:
+                props.merge(SelectionTopologyProperties::masses());
+                break;
+        }
+    }
+    return props;
+}
+
+
 /********************************************************************
  * SelectionCollection
  */
@@ -557,14 +612,15 @@ SelectionCollection::setDebugLevel(int debugLevel)
 
 
 void
-SelectionCollection::setTopology(t_topology *top, int natoms)
+SelectionCollection::setTopology(gmx_mtop_t *top, int natoms)
 {
     GMX_RELEASE_ASSERT(natoms > 0 || top != NULL,
                        "The number of atoms must be given if there is no topology");
+    checkTopologyProperties(top, requiredTopologyProperties());
     // Get the number of atoms from the topology if it is not given.
     if (natoms <= 0)
     {
-        natoms = top->atoms.nr;
+        natoms = top->natoms;
     }
     if (impl_->bExternalGroupsSet_)
     {
@@ -583,8 +639,8 @@ SelectionCollection::setTopology(t_topology *top, int natoms)
     gmx_ana_selcollection_t *sc = &impl_->sc_;
     // Do this first, as it allocates memory, while the others don't throw.
     gmx_ana_index_init_simple(&sc->gall, natoms);
-    sc->pcc.setTopology(top);
     sc->top = top;
+    sc->pcc.setTopology(top);
 }
 
 
@@ -614,46 +670,24 @@ SelectionCollection::setIndexGroups(gmx_ana_indexgrps_t *grps)
     }
 }
 
-
-bool
-SelectionCollection::requiresTopology() const
+SelectionTopologyProperties
+SelectionCollection::requiredTopologyProperties() const
 {
-    e_poscalc_t  type;
-    int          flags;
+    SelectionTopologyProperties props;
 
-    if (!impl_->rpost_.empty())
-    {
-        flags = 0;
-        // Should not throw, because has been checked earlier.
-        PositionCalculationCollection::typeFromEnum(impl_->rpost_.c_str(),
-                                                    &type, &flags);
-        if (type != POS_ATOM)
-        {
-            return true;
-        }
-    }
-    if (!impl_->spost_.empty())
-    {
-        flags = 0;
-        // Should not throw, because has been checked earlier.
-        PositionCalculationCollection::typeFromEnum(impl_->spost_.c_str(),
-                                                    &type, &flags);
-        if (type != POS_ATOM)
-        {
-            return true;
-        }
-    }
+    // These should not throw, because has been checked earlier.
+    props.merge(impl_->requiredTopologyPropertiesForPositionType(impl_->rpost_, false));
+    const bool forcesRequested = impl_->areForcesRequested();
+    props.merge(impl_->requiredTopologyPropertiesForPositionType(impl_->spost_,
+                                                                 forcesRequested));
 
     SelectionTreeElementPointer sel = impl_->sc_.root;
-    while (sel)
+    while (sel && !props.hasAll())
     {
-        if (_gmx_selelem_requires_top(*sel))
-        {
-            return true;
-        }
+        props.merge(sel->requiredTopologyProperties());
         sel = sel->next;
     }
-    return false;
+    return props;
 }
 
 
@@ -756,10 +790,7 @@ SelectionCollection::parseFromString(const std::string &str)
 void
 SelectionCollection::compile()
 {
-    if (impl_->sc_.top == NULL && requiresTopology())
-    {
-        GMX_THROW(InconsistentInputError("Selection requires topology information, but none provided"));
-    }
+    checkTopologyProperties(impl_->sc_.top, requiredTopologyProperties());
     if (!impl_->bExternalGroupsSet_)
     {
         setIndexGroups(NULL);
@@ -827,12 +858,15 @@ SelectionCollection::compile()
             }
         }
     }
+    impl_->rpost_.clear();
+    impl_->spost_.clear();
 }
 
 
 void
 SelectionCollection::evaluate(t_trxframe *fr, t_pbc *pbc)
 {
+    checkTopologyProperties(impl_->sc_.top, requiredTopologyProperties());
     if (fr->bIndex)
     {
         gmx_ana_index_t g;
index 57ffcb83759417cadc5323efe32a8c1b61801d55..44bb7e7727cf9da7389044208b5a7b6a672b4e30 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -52,8 +52,8 @@
 #include "gromacs/utility/classhelpers.h"
 
 struct gmx_ana_indexgrps_t;
+struct gmx_mtop_t;
 struct t_pbc;
-struct t_topology;
 struct t_trxframe;
 
 namespace gmx
@@ -64,6 +64,7 @@ class SelectionCompiler;
 class SelectionEvaluator;
 class TextInputStream;
 class TextOutputStream;
+struct SelectionTopologyProperties;
 
 /*! \brief
  * Collection of selections.
@@ -202,20 +203,22 @@ class SelectionCollection
         void setDebugLevel(int debugLevel);
 
         /*! \brief
-         * Returns true if the collection requires topology information for
-         * evaluation.
+         * Returns what topology information is required for evaluation.
          *
-         * \returns true if any selection in the collection requires topology
-         *      information.
+         * \returns What topology information is required for compiling and/or
+         *     evaluating the selections in the collection.
          *
          * Before the parser functions have been called, the return value is
          * based just on the position types set.
          * After parser functions have been called, the return value also takes
          * into account the selection keywords used.
+         * After the compiler has been called, the return value is final and
+         * also considers possible force evaluation requested for the
+         * selections.
          *
          * Does not throw.
          */
-        bool requiresTopology() const;
+        SelectionTopologyProperties requiredTopologyProperties() const;
         /*! \brief
          * Returns true if the collection requires external index groups.
          *
@@ -242,7 +245,7 @@ class SelectionCollection
          * Does not throw currently, but this is subject to change when more
          * underlying code is converted to C++.
          */
-        void setTopology(t_topology *top, int natoms);
+        void setTopology(gmx_mtop_t *top, int natoms);
         /*! \brief
          * Sets the external index groups to use for the selections.
          *
index 0cb7a665e9ca2bfe8212994b945a6f5e42d0b9f3..1492715dfec93cd8f5a67448eb28b03a7db26910 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -84,6 +84,55 @@ enum SelectionFlag
 typedef FlagsTemplate<SelectionFlag> SelectionFlags;
 //! \endcond
 
+/*! \brief
+ * Describes topology properties required for selection evaluation.
+ *
+ * See SelectionCollection::requiredTopologyProperties().
+ *
+ * \inpublicapi
+ * \ingroup module_selection
+ */
+struct SelectionTopologyProperties
+{
+    //! Returns a property object that requires generic topology info.
+    static SelectionTopologyProperties topology()
+    {
+        return SelectionTopologyProperties(true, false);
+    }
+    //! Returns a property object that requires atom masses.
+    static SelectionTopologyProperties masses()
+    {
+        return SelectionTopologyProperties(true, true);
+    }
+
+    //! Initializes properties that does not require anything.
+    SelectionTopologyProperties()
+        : needsTopology(false), needsMasses(false)
+    {
+    }
+    //! Initializes properties with the given flags.
+    SelectionTopologyProperties(bool needsTopology, bool needsMasses)
+        : needsTopology(needsTopology), needsMasses(needsMasses)
+    {
+    }
+
+    //! Combines flags from another properties object to this.
+    void merge(const SelectionTopologyProperties &other)
+    {
+        needsTopology = needsTopology || other.needsTopology;
+        needsMasses   = needsMasses || other.needsMasses;
+    }
+    //! Whether all flags are `true` (for short-ciruiting logic).
+    bool hasAll() const { return needsTopology && needsMasses; }
+    //! Whether any flag is `true`.
+    bool hasAny() const { return needsTopology || needsMasses; }
+
+    //! Whether topology information is needed for selection evaluation.
+    bool needsTopology;
+    //! Whether atom masses are needed for selection evaluation.
+    bool needsMasses;
+};
+
 }
 
 #endif
index 9d877945982e7116c878598a8f8e12467059afaf..2d45bf55f1da3a1c1993ea68b29672128df33c15 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -71,11 +71,14 @@ class SelectionFileOptionStorage : public AbstractOptionStorage
         virtual OptionInfo &optionInfo() { return info_; }
         virtual std::string typeString() const { return "file"; }
         virtual int valueCount() const { return 0; }
-        virtual std::string formatValue(int /*i*/) const { return ""; }
+        virtual std::vector<Variant> defaultValues() const { return {}; }
+        virtual std::vector<std::string> defaultValuesAsStrings() const { return {}; }
+        virtual std::vector<Variant>
+        normalizeValues(const std::vector<Variant> &values) const { return values; }
 
     private:
         virtual void clearSet();
-        virtual void convertValue(const std::string &value);
+        virtual void convertValue(const Variant &value);
         virtual void processSet();
         virtual void processAll() {}
 
index 019f8965b5e27b05807f99a00ba447d3030a149c..1343907baa3ef72cddf657079e1afd689b9df968 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -84,6 +84,13 @@ std::string SelectionOptionStorage::formatSingleValue(const Selection &value) co
 }
 
 
+std::vector<Variant>
+SelectionOptionStorage::normalizeValues(const std::vector<Variant> & /*values*/) const
+{
+    GMX_THROW(NotImplementedError("Selection options not supported in this context"));
+}
+
+
 void SelectionOptionStorage::addSelections(
         const SelectionList &selections,
         bool                 bFullValue)
@@ -118,9 +125,9 @@ void SelectionOptionStorage::addSelections(
 }
 
 
-void SelectionOptionStorage::convertValue(const std::string &value)
+void SelectionOptionStorage::convertValue(const Variant &value)
 {
-    manager_.convertOptionValue(this, value, false);
+    manager_.convertOptionValue(this, value.cast<std::string>(), false);
 }
 
 void SelectionOptionStorage::processSetValues(ValueList *values)
@@ -180,10 +187,9 @@ void SelectionOptionStorage::setAllowedValueCount(int count)
 
 void SelectionOptionStorage::setSelectionFlag(SelectionFlag flag, bool bSet)
 {
-    ValueList::iterator i;
-    for (i = values().begin(); i != values().end(); ++i)
+    for (const Selection &value : values())
     {
-        if (flag == efSelection_OnlyStatic && bSet && i->isDynamic())
+        if (flag == efSelection_OnlyStatic && bSet && value.isDynamic())
         {
             MessageStringCollector errors;
             errors.startContext("In option '" + name() + "'");
@@ -193,9 +199,9 @@ void SelectionOptionStorage::setSelectionFlag(SelectionFlag flag, bool bSet)
         }
     }
     selectionFlags_.set(flag, bSet);
-    for (i = values().begin(); i != values().end(); ++i)
+    for (Selection &value : values())
     {
-        i->data().setFlags(selectionFlags_);
+        value.data().setFlags(selectionFlags_);
     }
 }
 
@@ -281,7 +287,7 @@ void SelectionFileOptionStorage::clearSet()
     bValueParsed_ = false;
 }
 
-void SelectionFileOptionStorage::convertValue(const std::string &value)
+void SelectionFileOptionStorage::convertValue(const Variant &value)
 {
     if (bValueParsed_)
     {
@@ -289,7 +295,7 @@ void SelectionFileOptionStorage::convertValue(const std::string &value)
     }
     bValueParsed_ = true;
     // TODO: Should we throw an InvalidInputError if the file does not exist?
-    manager_.parseRequestedFromFile(value);
+    manager_.parseRequestedFromFile(value.cast<std::string>());
 }
 
 void SelectionFileOptionStorage::processSet()
index 32c80a2506ae49c609c17c410f3065c13bdfc82d..8de8667f1becac9c9976ed8a7a6b6288cd051be6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -54,6 +54,9 @@
 #include "gromacs/selection/selectioncollection.h"
 #include "gromacs/selection/selectionfileoption.h"
 #include "gromacs/selection/selectionoptionmanager.h"
+#include "gromacs/topology/atoms.h"
+#include "gromacs/topology/topology.h"
+#include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/filestream.h"
 
 namespace gmx
@@ -111,7 +114,7 @@ class SelectionOptionBehavior::Impl
             }
             if (ndxfile_.empty())
             {
-                t_topology *top = topologyProvider_.getTopology(false);
+                gmx_mtop_t *top = topologyProvider_.getTopology(false);
                 gmx_ana_indexgrps_init(&grps_, top, NULL);
             }
             else
@@ -132,14 +135,43 @@ class SelectionOptionBehavior::Impl
 
         void compileSelections()
         {
-            t_topology *top    = topologyProvider_.getTopology(selections_.requiresTopology());
-            int         natoms = -1;
+            const bool  topRequired = selections_.requiredTopologyProperties().needsTopology;
+            gmx_mtop_t *top         = topologyProvider_.getTopology(topRequired);
+            int         natoms      = -1;
             if (top == NULL)
             {
                 natoms = topologyProvider_.getAtomCount();
             }
+            getMassesIfRequired(top);
             selections_.setTopology(top, natoms);
             selections_.compile();
+            // Situation may have changed after compilation.
+            getMassesIfRequired(top);
+        }
+
+        void getMassesIfRequired(gmx_mtop_t *top)
+        {
+            const bool massRequired = selections_.requiredTopologyProperties().needsMasses;
+            if (!massRequired)
+            {
+                return;
+            }
+            // TODO: There can be some corner cases that still hit this assert
+            // when the user has not provided the topology.
+            GMX_RELEASE_ASSERT(top != nullptr,
+                               "Masses are required, but no topology is loaded");
+            for (int i = 0; i < top->nmoltype; ++i)
+            {
+                gmx_moltype_t &moltype = top->moltype[i];
+                if (!moltype.atoms.haveMass)
+                {
+                    atomsSetMassesBasedOnNames(&moltype.atoms, TRUE);
+                    if (!moltype.atoms.haveMass)
+                    {
+                        GMX_THROW(InconsistentInputError("Selections require mass information for evaluation, but it is not available in the input and could not be determined for all atoms based on atom names."));
+                    }
+                }
+            }
         }
 
         SelectionCollection    &selections_;
index 4bcc45e1ddb475c388f959f624b9019044e9c21f..1768a01b46e964dad1c4ca01de75b50cc93353c6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -48,7 +48,7 @@
 #include "gromacs/options/ioptionsbehavior.h"
 #include "gromacs/utility/classhelpers.h"
 
-struct t_topology;
+struct gmx_mtop_t;
 
 namespace gmx
 {
@@ -93,7 +93,7 @@ class ITopologyProvider
          * different values of \p required.  Subsequent calls should just
          * return the same topology that was loaded in the first call.
          */
-        virtual t_topology *getTopology(bool required) = 0;
+        virtual gmx_mtop_t *getTopology(bool required) = 0;
         /*! \brief
          * Returns the number of atoms.
          *
index a31859b59baec6dc1aefddd4cfcf6951e2ffd403..54d43a4cc554a940e022809bba3ba4cf8a32bb9a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -246,7 +246,7 @@ void SelectionOptionManager::Impl::requestUnsetRequiredOptions()
         SelectionOptionStorage &storage = **i;
         if (storage.isRequired() && !storage.isSet())
         {
-            requests_.push_back(SelectionRequest(&storage));
+            requests_.emplace_back(&storage);
         }
     }
 }
@@ -285,7 +285,7 @@ void
 SelectionOptionManager::requestOptionDelayedParsing(
         SelectionOptionStorage *storage)
 {
-    impl_->requests_.push_back(Impl::SelectionRequest(storage));
+    impl_->requests_.emplace_back(storage);
 }
 
 bool
index 0ef88da0a6411f22300bf8d79a2c30c333aa5fb7..795bdffa4c90cc53ecd627ab2ebcd2d2122b1e9b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -77,6 +77,8 @@ class SelectionOptionStorage : public OptionStorageTemplate<Selection>
         virtual OptionInfo &optionInfo() { return info_; }
         virtual std::string typeString() const { return "selection"; }
         virtual std::string formatSingleValue(const Selection &value) const;
+        virtual std::vector<Variant>
+        normalizeValues(const std::vector<Variant> &values) const;
 
         /*! \brief
          * Adds selections to the storage.
@@ -126,7 +128,7 @@ class SelectionOptionStorage : public OptionStorageTemplate<Selection>
         void setSelectionFlag(SelectionFlag flag, bool bSet);
 
     private:
-        virtual void convertValue(const std::string &value);
+        virtual void convertValue(const Variant &value);
         virtual void processSetValues(ValueList *values);
         virtual void processAll();
 
index f514c79daa6cdb07558f44ada499fc375c6d945a..2c81620370e427ae2ddb8fdd780b32dcd51b70a4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -47,6 +47,7 @@
 
 #include "gromacs/selection/indexutil.h"
 #include "gromacs/selection/position.h"
+#include "gromacs/selection/selectionenums.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/smalloc.h"
@@ -136,6 +137,7 @@ SelectionTreeElement::SelectionTreeElement(e_selelem_t              type,
                                            const SelectionLocation &location)
     : location_(location)
 {
+    // cppcheck-suppress useInitializationList
     this->type       = type;
     this->flags      = (type != SEL_ROOT) ? SEL_ALLOCVAL : 0;
     if (type == SEL_BOOLEAN)
@@ -324,6 +326,45 @@ void SelectionTreeElement::fillNameIfMissing(const char *selectionText)
     }
 }
 
+SelectionTopologyProperties
+SelectionTreeElement::requiredTopologyProperties() const
+{
+    SelectionTopologyProperties props;
+    if (type == SEL_EXPRESSION || type == SEL_MODIFIER)
+    {
+        bool needsTop    = false;
+        bool needsMasses = false;
+        if (u.expr.method != nullptr)
+        {
+            needsTop    = (u.expr.method->flags & SMETH_REQTOP);
+            needsMasses = (u.expr.method->flags & SMETH_REQMASS);
+        }
+        if (u.expr.pc != nullptr)
+        {
+            auto requiredTopologyInfo = gmx_ana_poscalc_required_topology_info(u.expr.pc);
+            needsTop    = needsTop
+                || (requiredTopologyInfo != PositionCalculationCollection::RequiredTopologyInfo::None);
+            needsMasses = needsMasses
+                || (requiredTopologyInfo == PositionCalculationCollection::RequiredTopologyInfo::TopologyAndMasses);
+        }
+        if (needsTop)
+        {
+            props.merge(SelectionTopologyProperties::topology());
+        }
+        if (needsMasses)
+        {
+            props.merge(SelectionTopologyProperties::masses());
+        }
+    }
+    SelectionTreeElementPointer child = this->child;
+    while (child && !props.hasAll())
+    {
+        props.merge(child->requiredTopologyProperties());
+        child = child->next;
+    }
+    return props;
+}
+
 void SelectionTreeElement::checkUnsortedAtoms(
         bool bUnsortedAllowed, ExceptionInitializer *errors) const
 {
@@ -737,34 +778,3 @@ _gmx_selelem_print_tree(FILE *fp, const gmx::SelectionTreeElement &sel,
         child = child->next;
     }
 }
-
-/*!
- * \param[in] root Root of the subtree to query.
- * \returns true if \p root or any any of its elements require topology
- *   information, false otherwise.
- */
-bool
-_gmx_selelem_requires_top(const gmx::SelectionTreeElement &root)
-{
-    if (root.type == SEL_EXPRESSION || root.type == SEL_MODIFIER)
-    {
-        if (root.u.expr.method && (root.u.expr.method->flags & SMETH_REQTOP))
-        {
-            return true;
-        }
-        if (root.u.expr.pc && gmx_ana_poscalc_requires_top(root.u.expr.pc))
-        {
-            return true;
-        }
-    }
-    gmx::SelectionTreeElementPointer child = root.child;
-    while (child)
-    {
-        if (_gmx_selelem_requires_top(*child))
-        {
-            return true;
-        }
-        child = child->next;
-    }
-    return false;
-}
index 62838a5d09b95d242ed004d68c9c87da50b8855f..d6b63ed6b5cf84b93cc3826321142d1efbe8c7b2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -70,6 +70,7 @@ struct t_compiler_data;
 namespace gmx
 {
 class SelectionTreeElement;
+struct SelectionTopologyProperties;
 
 //! Smart pointer type for selection tree element pointers.
 typedef std::shared_ptr<SelectionTreeElement> SelectionTreeElementPointer;
@@ -356,6 +357,13 @@ class SelectionTreeElement
          */
         void fillNameIfMissing(const char *selectionText);
 
+        /*! \brief
+         * Returns which topology properties the selection element subtree requires
+         * for evaluation.
+         *
+         * \returns   List of topology properties required for evaluation.
+         */
+        SelectionTopologyProperties requiredTopologyProperties() const;
         /*! \brief
          * Checks that this element and its children do not contain unsupported
          * elements with unsorted atoms.
@@ -536,10 +544,6 @@ void
 _gmx_selelem_print_compiler_info(FILE *fp, const gmx::SelectionTreeElement &sel,
                                  int level);
 
-/** Returns true if the selection element subtree requires topology information for evaluation. */
-bool
-_gmx_selelem_requires_top(const gmx::SelectionTreeElement &root);
-
 /* In sm_insolidangle.c */
 /** Returns true if the covered fraction of the selection can be calculated. */
 bool
index d5142d6aae2f6747820c33b71fe3103ec4ccc4e7..4b5515308980e53a24565e8bce4014b363f8594f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  *    and the \p top pointer passed to the callbacks is guaranteed to be
  *    non-NULL. Should be set if the method requires topology information
  *    for evaluation.
+ *  - \ref SMETH_REQMASS : If set, masses of atoms is always loaded
+ *    and the \p top pointer passed to the callbacks is guaranteed to be
+ *    non-NULL and have meaningful masses.  Should be set if the method requires
+ *    atom masses for evaluation.  Implies \ref SMETH_REQTOP.
  *  - \ref SMETH_DYNAMIC : If set, the method can only be evaluated dynamically,
  *    i.e., it requires data from the trajectory frame.
  *  - \ref SMETH_MODIFIER : If set, the method is a selection modifier and
 #include "selparam.h"
 #include "selvalue.h"
 
-namespace gmx
-{
-class PositionCalculationCollection;
-class SelectionParserSymbolTable;
-} // namespace gmx
-
 struct gmx_ana_index_t;
 struct gmx_ana_pos_t;
 struct gmx_ana_selcollection_t;
+struct gmx_mtop_t;
 struct t_pbc;
-struct t_topology;
 struct t_trxframe;
 
+namespace gmx
+{
+class PositionCalculationCollection;
+class SelectionParserSymbolTable;
+
+/*! \internal
+ * \brief
+ * Evaluation context for selection methods.
+ *
+ * This structure encapsulates common parameters passed to selection method
+ * evaluation functions.  The contained values describe the evaluation context,
+ * i.e., the topology and the current trajectory frame.
+ *
+ * \ingroup module_selection
+ */
+struct SelMethodEvalContext
+{
+    //! Initializes the context with given values.
+    SelMethodEvalContext(const gmx_mtop_t *top, t_trxframe *fr, const t_pbc *pbc)
+        : top(top), fr(fr), pbc(pbc)
+    {
+    }
+
+    /*! \brief
+     * Topology.
+     *
+     * Can be NULL if \ref SMETH_REQTOP or \ref SMETH_REQMASS is not set for
+     * the method.
+     */
+    const gmx_mtop_t *top;
+    /*! \brief
+     * Trajectory frame.
+     *
+     * For static methods that are evaluated based on topology information
+     * alone, this is `NULL`.
+     */
+    t_trxframe       *fr;
+    /*! \brief
+     * Periodic boundary condition information.
+     *
+     * Can be `NULL`, in which case PBC should not be used.
+     */
+    const t_pbc      *pbc;
+};
+
+} // namespace gmx
+
 /*! \name Selection method flags
  * \anchor selmethod_flags
  */
 /*@{*/
-/*! \brief
- * If set, the method requires topology information.
- */
+//! If set, the method requires topology information.
 #define SMETH_REQTOP     1
-/*! \brief
- * If set, the method can only be evaluated dynamically.
- */
-#define SMETH_DYNAMIC    2
+//! If set, the method requires atom masses.
+#define SMETH_REQMASS    2
+//! If set, the method can only be evaluated dynamically.
+#define SMETH_DYNAMIC    4
 /*! \brief
  * If set, the method evaluates to a single value.
  *
  * The default is that the method evaluates to a value for each input atom.
  * Cannot be combined with \ref SMETH_VARNUMVAL.
  */
-#define SMETH_SINGLEVAL  4
+#define SMETH_SINGLEVAL  8
 /*! \brief
  * If set, the method evaluates to an arbitrary number of values.
  *
  * The default is that the method evaluates to a value for each input atom.
  * Cannot be combined with \ref SMETH_SINGLEVAL or with \ref GROUP_VALUE.
  */
-#define SMETH_VARNUMVAL  8
+#define SMETH_VARNUMVAL  16
 /*! \brief
  * If set, the method evaluates to single-character strings.
  *
@@ -418,7 +461,7 @@ typedef void  (*sel_posfunc)(gmx::PositionCalculationCollection *pcc, void *data
  * Does initialization based on topology and/or parameter values.
  *
  * \param[in]  top   Topology structure
- *   (can be NULL if \ref SMETH_REQTOP is not set).
+ *   (can be NULL if \ref SMETH_REQTOP or \ref SMETH_REQMASS is not set).
  * \param[in]  npar  Number of parameters in \p param.
  * \param[in]  param Pointer to (an initialized copy of) the method's
  *   \c gmx_ana_selmethod_t::param.
@@ -458,13 +501,13 @@ typedef void  (*sel_posfunc)(gmx::PositionCalculationCollection *pcc, void *data
  * This function may be called multiple times for the same method if the
  * method takes parameters with \ref SPAR_ATOMVAL set.
  */
-typedef void  (*sel_initfunc)(t_topology *top, int npar,
+typedef void  (*sel_initfunc)(const gmx_mtop_t *top, int npar,
                               gmx_ana_selparam_t *param, void *data);
 /*! \brief
  * Initializes output data structure.
  *
  * \param[in]     top   Topology structure
- *   (can be NULL if \ref SMETH_REQTOP is not set).
+ *   (can be NULL if \ref SMETH_REQTOP or \ref SMETH_REQMASS is not set).
  * \param[in,out] out   Output data structure.
  * \param[in]     data  Internal data structure from sel_datafunc().
  * \returns       0 on success, an error code on error.
@@ -487,7 +530,7 @@ typedef void  (*sel_initfunc)(t_topology *top, int npar,
  * This function may be called multiple times for the same method if the
  * method takes parameters with \ref SPAR_ATOMVAL set.
  */
-typedef void  (*sel_outinitfunc)(t_topology *top, gmx_ana_selvalue_t *out,
+typedef void  (*sel_outinitfunc)(const gmx_mtop_t *top, gmx_ana_selvalue_t *out,
                                  void *data);
 /*! \brief
  * Frees the internal data.
@@ -511,11 +554,7 @@ typedef void  (*sel_freefunc)(void *data);
 /*! \brief
  * Initializes the evaluation for a new frame.
  *
- * \param[in]  top  Topology structure
- *   (can be NULL if \ref SMETH_REQTOP is not set).
- * \param[in]  fr   Current frame.
- * \param[in]  pbc  Initialized periodic boundary condition structure,
- *   or NULL if PBC should not be used.
+ * \param[in]  context  Evaluation context.
  * \param      data Internal data structure from sel_datafunc().
  * \returns    0 on success, a non-zero error code on failure.
  *
@@ -530,16 +569,12 @@ typedef void  (*sel_freefunc)(void *data);
  * For static methods, it is called once, with \p fr and \p pbc set to
  * NULL.
  */
-typedef void  (*sel_framefunc)(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                               void *data);
+typedef void  (*sel_framefunc)(const gmx::SelMethodEvalContext &context,
+                               void                            *data);
 /*! \brief
  * Evaluates a selection method.
  *
- * \param[in]  top  Topology structure
- *   (can be NULL if \ref SMETH_REQTOP is not set).
- * \param[in]  fr   Current frame.
- * \param[in]  pbc  Initialized periodic boundary condition structure,
- *   or NULL if PBC should not be used.
+ * \param[in]  context  Evaluation context.
  * \param[in]  g    Index group for which the method should be evaluated.
  * \param[out] out  Output data structure.
  * \param      data Internal data structure from sel_datafunc().
@@ -562,17 +597,13 @@ typedef void  (*sel_framefunc)(t_topology *top, t_trxframe *fr, t_pbc *pbc,
  * contains such an atom in case the \p fr has been loaded from a trajectory
  * that only contains a subset of the system.
  */
-typedef void  (*sel_updatefunc)(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+typedef void  (*sel_updatefunc)(const gmx::SelMethodEvalContext &context,
                                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out,
                                 void *data);
 /*! \brief
  * Evaluates a selection method using positions.
  *
- * \param[in]  top  Topology structure
- *   (can be NULL if \ref SMETH_REQTOP is not set).
- * \param[in]  fr   Current frame.
- * \param[in]  pbc  Initialized periodic boundary condition structure,
- *   or NULL if PBC should not be used.
+ * \param[in]  context  Evaluation context.
  * \param[in]  pos  Positions for which the method should be evaluated.
  * \param[out] out  Output data structure.
  * \param      data Internal data structure from sel_datafunc().
@@ -596,7 +627,7 @@ typedef void  (*sel_updatefunc)(t_topology *top, t_trxframe *fr, t_pbc *pbc,
  * contains such an atom in case the \p fr has been loaded from a trajectory
  * that only contains a subset of the system.
  */
-typedef void  (*sel_updatefunc_pos)(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+typedef void  (*sel_updatefunc_pos)(const gmx::SelMethodEvalContext &context,
                                     gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out,
                                     void *data);
 
index 05cb8c72b4655061c336112233b501f070acb123..c92a940e02864adbbee4f656764a041271c5cd05 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -124,13 +124,20 @@ init_data_compare(int npar, gmx_ana_selparam_t *param);
  * \returns   0 if the input data is valid, -1 on error.
  */
 static void
-init_compare(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+init_compare(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
 /** Frees the memory allocated for comparison expression evaluation. */
 static void
 free_data_compare(void *data);
-/** Evaluates comparison expressions. */
+/*! \brief
+ * Evaluates comparison expressions.
+ *
+ * \param[in]  context  Not used.
+ * \param[in]  g        Evaluation index group.
+ * \param[out] out      Output data structure (\p out->u.g is used).
+ * \param[in]  data     Should point to a \c t_methoddata_compare.
+ */
 static void
-evaluate_compare(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_compare(const gmx::SelMethodEvalContext &context,
                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
 
 /** Parameters for comparison expression evaluation. */
@@ -409,7 +416,7 @@ convert_real_int(int n, t_compare_value *val, e_comparison_t cmpt, bool bRight)
 }
 
 static void
-init_compare(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
+init_compare(const gmx_mtop_t * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
 {
     t_methoddata_compare *d = (t_methoddata_compare *)data;
     int                   n1, n2;
@@ -503,25 +510,18 @@ free_data_compare(void *data)
 /*! \brief
  * Implementation for evaluate_compare() for integer values.
  *
- * \param[in]  top   Not used.
- * \param[in]  fr    Not used.
- * \param[in]  pbc   Not used.
  * \param[in]  g     Evaluation index group.
  * \param[out] out   Output data structure (\p out->u.g is used).
  * \param[in]  data  Should point to a \c t_methoddata_compare.
  */
 static void
-evaluate_compare_int(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+evaluate_compare_int(gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
 {
     t_methoddata_compare *d = (t_methoddata_compare *)data;
     int                   i, i1, i2, ig;
     int                   a, b;
     bool                  bAccept;
 
-    GMX_UNUSED_VALUE(top);
-    GMX_UNUSED_VALUE(fr);
-    GMX_UNUSED_VALUE(pbc);
     for (i = i1 = i2 = ig = 0; i < g->isize; ++i)
     {
         a       = d->left.i[i1];
@@ -556,9 +556,6 @@ evaluate_compare_int(t_topology *top, t_trxframe *fr, t_pbc *pbc,
 /*! \brief
  * Implementation for evaluate_compare() if either value is non-integer.
  *
- * \param[in]  top   Not used.
- * \param[in]  fr    Not used.
- * \param[in]  pbc   Not used.
  * \param[in]  g     Evaluation index group.
  * \param[out] out   Output data structure (\p out->u.g is used).
  * \param[in]  data  Should point to a \c t_methoddata_compare.
@@ -567,17 +564,13 @@ evaluate_compare_int(t_topology *top, t_trxframe *fr, t_pbc *pbc,
  * This is ensured by the initialization method.
  */
 static void
-evaluate_compare_real(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                      gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+evaluate_compare_real(gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
 {
     t_methoddata_compare *d = (t_methoddata_compare *)data;
     int                   i, i1, i2, ig;
     real                  a, b;
     bool                  bAccept;
 
-    GMX_UNUSED_VALUE(top);
-    GMX_UNUSED_VALUE(fr);
-    GMX_UNUSED_VALUE(pbc);
     for (i = i1 = i2 = ig = 0; i < g->isize; ++i)
     {
         a       = d->left.r[i1];
@@ -609,26 +602,18 @@ evaluate_compare_real(t_topology *top, t_trxframe *fr, t_pbc *pbc,
     out->u.g->isize = ig;
 }
 
-/*!
- * \param[in]  top   Not used.
- * \param[in]  fr    Not used.
- * \param[in]  pbc   Not used.
- * \param[in]  g     Evaluation index group.
- * \param[out] out   Output data structure (\p out->u.g is used).
- * \param[in]  data  Should point to a \c t_methoddata_compare.
- */
 static void
-evaluate_compare(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_compare(const gmx::SelMethodEvalContext & /*context*/,
                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
 {
     t_methoddata_compare *d = (t_methoddata_compare *)data;
 
     if (!((d->left.flags | d->right.flags) & CMP_REALVAL))
     {
-        evaluate_compare_int(top, fr, pbc, g, out, data);
+        evaluate_compare_int(g, out, data);
     }
     else
     {
-        evaluate_compare_real(top, fr, pbc, g, out, data);
+        evaluate_compare_real(g, out, data);
     }
 }
index e98d85c8ae0d299b676db116e53d7b53d956b896..738657c92f051fd9cf11fa8da9407d0d0bae0c12 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -108,7 +108,7 @@ init_data_common(int npar, gmx_ana_selparam_t *param);
  * Also checks that the cutoff is valid.
  */
 static void
-init_common(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+init_common(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
 /** Frees the data allocated for a distance-based selection method. */
 static void
 free_data_common(void *data);
@@ -116,23 +116,21 @@ free_data_common(void *data);
  * Initializes the evaluation of a distance-based within selection method for a
  * frame.
  *
- * \param[in]  top  Not used.
- * \param[in]  fr   Current frame.
- * \param[in]  pbc  PBC structure.
- * \param      data Should point to a \c t_methoddata_distance.
+ * \param[in]  context Evaluation context.
+ * \param      data    Should point to a \c t_methoddata_distance.
  * \returns    0 on success, a non-zero error code on error.
  *
  * Initializes the neighborhood search for the current frame.
  */
 static void
-init_frame_common(t_topology *top, t_trxframe * fr, t_pbc *pbc, void *data);
+init_frame_common(const gmx::SelMethodEvalContext &context, void *data);
 /** Evaluates the \p distance selection method. */
 static void
-evaluate_distance(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_distance(const gmx::SelMethodEvalContext & /*context*/,
                   gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
 /** Evaluates the \p within selection method. */
 static void
-evaluate_within(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_within(const gmx::SelMethodEvalContext & /*context*/,
                 gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
 
 /** Parameters for the \p distance selection method. */
@@ -234,7 +232,7 @@ init_data_common(int /* npar */, gmx_ana_selparam_t *param)
 }
 
 static void
-init_common(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
+init_common(const gmx_mtop_t * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
 {
     t_methoddata_distance *d = static_cast<t_methoddata_distance *>(data);
 
@@ -258,13 +256,13 @@ free_data_common(void *data)
 }
 
 static void
-init_frame_common(t_topology * /* top */, t_trxframe * /* fr */, t_pbc *pbc, void *data)
+init_frame_common(const gmx::SelMethodEvalContext &context, void *data)
 {
     t_methoddata_distance *d = static_cast<t_methoddata_distance *>(data);
 
     d->nbsearch.reset();
     gmx::AnalysisNeighborhoodPositions pos(d->p.x, d->p.count());
-    d->nbsearch = d->nb.initSearch(pbc, pos);
+    d->nbsearch = d->nb.initSearch(context.pbc, pos);
 }
 
 /*!
@@ -275,7 +273,7 @@ init_frame_common(t_topology * /* top */, t_trxframe * /* fr */, t_pbc *pbc, voi
  * and puts them in \p out->u.r.
  */
 static void
-evaluate_distance(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_distance(const gmx::SelMethodEvalContext & /*context*/,
                   gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data)
 {
     t_methoddata_distance *d = static_cast<t_methoddata_distance *>(data);
@@ -295,7 +293,7 @@ evaluate_distance(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc
  * \c t_methoddata_distance::xref and puts them in \p out.g.
  */
 static void
-evaluate_within(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_within(const gmx::SelMethodEvalContext & /*context*/,
                 gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data)
 {
     t_methoddata_distance *d = static_cast<t_methoddata_distance *>(data);
index 196a6575eb84a89ead8134c2c7cb90f64c1487dc..3bb50305f3a62af73f19a26e016e86966a50e9cc 100644 (file)
@@ -257,29 +257,27 @@ init_data_insolidangle(int npar, gmx_ana_selparam_t *param);
  * and allocates memory for the bins used during the evaluation.
  */
 static void
-init_insolidangle(t_topology * top, int npar, gmx_ana_selparam_t * param, void *data);
+init_insolidangle(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t * param, void *data);
 /** Frees the data allocated for the \p insolidangle selection method. */
 static void
 free_data_insolidangle(void *data);
 /*! \brief
  * Initializes the evaluation of the \p insolidangle selection method for a frame.
  *
- * \param[in]  top  Not used.
- * \param[in]  fr   Not used.
- * \param[in]  pbc  PBC structure.
- * \param      data Should point to a \ref t_methoddata_insolidangle.
+ * \param[in]  context Evaluation context.
+ * \param      data    Should point to a \ref t_methoddata_insolidangle.
  *
  * Creates a lookup structure that enables fast queries of whether a point
  * is within the solid angle or not.
  */
 static void
-init_frame_insolidangle(t_topology * top, t_trxframe * fr, t_pbc *pbc, void *data);
+init_frame_insolidangle(const gmx::SelMethodEvalContext &context, void *data);
 /** Internal helper function for evaluate_insolidangle(). */
 static bool
-accept_insolidangle(rvec x, t_pbc *pbc, void *data);
+accept_insolidangle(rvec x, const t_pbc *pbc, void *data);
 /** Evaluates the \p insolidangle selection method. */
 static void
-evaluate_insolidangle(t_topology * /* top */, t_trxframe * /* fr */, t_pbc *pbc,
+evaluate_insolidangle(const gmx::SelMethodEvalContext &context,
                       gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
 
 /** Calculates the distance between unit vectors. */
@@ -404,7 +402,7 @@ init_data_insolidangle(int /* npar */, gmx_ana_selparam_t *param)
 }
 
 static void
-init_insolidangle(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t * /* param */, void *data)
+init_insolidangle(const gmx_mtop_t * /* top */, int /* npar */, gmx_ana_selparam_t * /* param */, void *data)
 {
     t_methoddata_insolidangle *surf = (t_methoddata_insolidangle *)data;
     int                        i, c;
@@ -462,7 +460,7 @@ free_data_insolidangle(void *data)
 }
 
 static void
-init_frame_insolidangle(t_topology * /* top */, t_trxframe * /* fr */, t_pbc *pbc, void *data)
+init_frame_insolidangle(const gmx::SelMethodEvalContext &context, void *data)
 {
     t_methoddata_insolidangle *d = (t_methoddata_insolidangle *)data;
     rvec                       dx;
@@ -472,9 +470,9 @@ init_frame_insolidangle(t_topology * /* top */, t_trxframe * /* fr */, t_pbc *pb
     clear_surface_points(d);
     for (i = 0; i < d->span.count(); ++i)
     {
-        if (pbc)
+        if (context.pbc)
         {
-            pbc_dx(pbc, d->span.x[i], d->center.x[0], dx);
+            pbc_dx(context.pbc, d->span.x[i], d->center.x[0], dx);
         }
         else
         {
@@ -494,7 +492,7 @@ init_frame_insolidangle(t_topology * /* top */, t_trxframe * /* fr */, t_pbc *pb
  * \returns   true if \p x is within the solid angle, false otherwise.
  */
 static bool
-accept_insolidangle(rvec x, t_pbc *pbc, void *data)
+accept_insolidangle(rvec x, const t_pbc *pbc, void *data)
 {
     t_methoddata_insolidangle *d = (t_methoddata_insolidangle *)data;
     rvec                       dx;
@@ -520,13 +518,13 @@ accept_insolidangle(rvec x, t_pbc *pbc, void *data)
  * \c t_methoddata_insolidangle::center, and stores the result in \p out->u.g.
  */
 static void
-evaluate_insolidangle(t_topology * /* top */, t_trxframe * /* fr */, t_pbc *pbc,
+evaluate_insolidangle(const gmx::SelMethodEvalContext &context,
                       gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data)
 {
     out->u.g->isize = 0;
     for (int b = 0; b < pos->count(); ++b)
     {
-        if (accept_insolidangle(pos->x[b], pbc, data))
+        if (accept_insolidangle(pos->x[b], context.pbc, data))
         {
             gmx_ana_pos_add_to_group(out->u.g, pos, b);
         }
index 5dbfc1833bcba4bd1d3783e5dc658bbace292345..e675249a4c1dc5cd4415a0f5f51049a85df72a69 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -104,7 +104,7 @@ init_data_kwstr(int npar, gmx_ana_selparam_t * param);
  * \param[in] data  Should point to \ref t_methoddata_kwint.
  */
 static void
-init_kwint(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+init_kwint(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
 /*! \brief
  * Initializes data for real keyword evaluation.
  *
@@ -115,7 +115,7 @@ init_kwint(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
  * \returns   0 (the initialization always succeeds).
  */
 static void
-init_kwreal(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+init_kwreal(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
 /*! \brief
  * Initializes data for string keyword evaluation.
  *
@@ -125,21 +125,21 @@ init_kwreal(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
  * \param[in] data  Should point to t_methoddata_kwstr.
  */
 static void
-init_kwstr(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+init_kwstr(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
 /** Frees the memory allocated for string keyword evaluation. */
 static void
 free_data_kwstr(void *data);
 /** Evaluates integer selection keywords. */
 static void
-evaluate_keyword_int(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_keyword_int(const gmx::SelMethodEvalContext &context,
                      gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
 /** Evaluates real selection keywords. */
 static void
-evaluate_keyword_real(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_keyword_real(const gmx::SelMethodEvalContext &context,
                       gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
 /** Evaluates string selection keywords. */
 static void
-evaluate_keyword_str(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_keyword_str(const gmx::SelMethodEvalContext &context,
                      gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
 
 /*! \internal \brief
@@ -347,7 +347,7 @@ gmx_ana_selmethod_t sm_keyword_str = {
  * Calls the initialization method of the wrapped keyword.
  */
 static void
-init_kweval(t_topology *top, int npar, gmx_ana_selparam_t * param, void *data);
+init_kweval(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t * param, void *data);
 /*! \brief
  * Initializes output for keyword evaluation in an arbitrary group.
  *
@@ -357,13 +357,13 @@ init_kweval(t_topology *top, int npar, gmx_ana_selparam_t * param, void *data);
  * \returns       0 for success.
  */
 static void
-init_output_kweval(t_topology *top, gmx_ana_selvalue_t *out, void *data);
+init_output_kweval(const gmx_mtop_t *top, gmx_ana_selvalue_t *out, void *data);
 /** Frees the data allocated for keyword evaluation in an arbitrary group. */
 static void
 free_data_kweval(void *data);
 /** Initializes frame evaluation for keyword evaluation in an arbitrary group. */
 static void
-init_frame_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data);
+init_frame_kweval(const gmx::SelMethodEvalContext &context, void *data);
 /*! \brief
  * Evaluates keywords in an arbitrary group.
  *
@@ -375,7 +375,7 @@ init_frame_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data);
  * evaluation group.
  */
 static void
-evaluate_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc, gmx_ana_index_t *g,
+evaluate_kweval(const gmx::SelMethodEvalContext &context, gmx_ana_index_t *g,
                 gmx_ana_selvalue_t *out, void *data);
 /*! \brief
  * Evaluates keywords in an arbitrary set of positions.
@@ -388,7 +388,7 @@ evaluate_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc, gmx_ana_index_t *g,
  * evaluation positions.
  */
 static void
-evaluate_kweval_pos(t_topology *top, t_trxframe *fr, t_pbc *pbc, gmx_ana_index_t *g,
+evaluate_kweval_pos(const gmx::SelMethodEvalContext &context, gmx_ana_index_t *g,
                     gmx_ana_selvalue_t *out, void *data);
 
 /*! \internal \brief
@@ -441,7 +441,7 @@ init_data_kwint(int  /* npar */, gmx_ana_selparam_t * /* param */)
 }
 
 static void
-init_kwint(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
+init_kwint(const gmx_mtop_t * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
 {
     t_methoddata_kwint *d = (t_methoddata_kwint *)data;
 
@@ -459,7 +459,7 @@ init_kwint(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, vo
  * Matching atoms are stored in \p out->u.g.
  */
 static void
-evaluate_keyword_int(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_keyword_int(const gmx::SelMethodEvalContext & /*context*/,
                      gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
 {
     t_methoddata_kwint *d = (t_methoddata_kwint *)data;
@@ -516,7 +516,7 @@ init_data_kwreal(int /* npar */, gmx_ana_selparam_t * /* param */)
 }
 
 static void
-init_kwreal(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
+init_kwreal(const gmx_mtop_t * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
 {
     t_methoddata_kwreal *d = (t_methoddata_kwreal *)data;
 
@@ -534,7 +534,7 @@ init_kwreal(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, v
  * Matching atoms are stored in \p out->u.g.
  */
 static void
-evaluate_keyword_real(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_keyword_real(const gmx::SelMethodEvalContext & /*context*/,
                       gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
 {
     t_methoddata_kwreal *d = (t_methoddata_kwreal *)data;
@@ -610,7 +610,7 @@ _gmx_selelem_set_kwstr_match_type(const gmx::SelectionTreeElementPointer &sel,
 }
 
 static void
-init_kwstr(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
+init_kwstr(const gmx_mtop_t * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
 {
     t_methoddata_kwstr *d = static_cast<t_methoddata_kwstr *>(data);
 
@@ -625,7 +625,7 @@ init_kwstr(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, vo
     for (int i = 0; i < n; ++i)
     {
         const char *s = param[1].val.u.s[i];
-        d->matches.push_back(StringKeywordMatchItem(d->matchType, s));
+        d->matches.emplace_back(d->matchType, s);
     }
 }
 
@@ -649,7 +649,7 @@ free_data_kwstr(void *data)
  * Matching atoms are stored in \p out->u.g.
  */
 static void
-evaluate_keyword_str(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_keyword_str(const gmx::SelMethodEvalContext & /*context*/,
                      gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
 {
     t_methoddata_kwstr *d = static_cast<t_methoddata_kwstr *>(data);
@@ -674,7 +674,7 @@ evaluate_keyword_str(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* p
  ********************************************************************/
 
 static void
-init_kweval(t_topology *top, int /* npar */, gmx_ana_selparam_t * /* param */, void *data)
+init_kweval(const gmx_mtop_t *top, int /* npar */, gmx_ana_selparam_t * /* param */, void *data)
 {
     t_methoddata_kweval *d = static_cast<t_methoddata_kweval *>(data);
 
@@ -682,7 +682,7 @@ init_kweval(t_topology *top, int /* npar */, gmx_ana_selparam_t * /* param */, v
 }
 
 static void
-init_output_kweval(t_topology * /* top */, gmx_ana_selvalue_t *out, void *data)
+init_output_kweval(const gmx_mtop_t * /* top */, gmx_ana_selvalue_t *out, void *data)
 {
     t_methoddata_kweval *d = static_cast<t_methoddata_kweval *>(data);
 
@@ -704,39 +704,33 @@ free_data_kweval(void *data)
 }
 
 /*!
- * \param[in]  top  Topology.
- * \param[in]  fr   Current frame.
- * \param[in]  pbc  PBC structure.
+ * \param[in]  context  Evaluation context.
  * \param      data Should point to a \ref t_methoddata_kweval.
- * \returns    0 on success, a non-zero error code on error.
- *
- * Creates a lookup structure that enables fast queries of whether a point
- * is within the solid angle or not.
  */
 static void
-init_frame_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data)
+init_frame_kweval(const gmx::SelMethodEvalContext &context, void *data)
 {
     t_methoddata_kweval *d = static_cast<t_methoddata_kweval *>(data);
 
-    d->kwmethod->init_frame(top, fr, pbc, d->kwmdata);
+    d->kwmethod->init_frame(context, d->kwmdata);
 }
 
 static void
-evaluate_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_kweval(const gmx::SelMethodEvalContext &context,
                 gmx_ana_index_t * /* g */, gmx_ana_selvalue_t *out, void *data)
 {
     t_methoddata_kweval *d = static_cast<t_methoddata_kweval *>(data);
 
-    d->kwmethod->update(top, fr, pbc, &d->g, out, d->kwmdata);
+    d->kwmethod->update(context, &d->g, out, d->kwmdata);
 }
 
 static void
-evaluate_kweval_pos(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_kweval_pos(const gmx::SelMethodEvalContext &context,
                     gmx_ana_index_t * /* g */, gmx_ana_selvalue_t *out, void *data)
 {
     t_methoddata_kweval *d = static_cast<t_methoddata_kweval *>(data);
 
-    d->kwmethod->pupdate(top, fr, pbc, &d->p, out, d->kwmdata);
+    d->kwmethod->pupdate(context, &d->p, out, d->kwmdata);
 }
 
 /*! \brief
index 5be901d7aea51eb70dc629a516fa2e58d206d729..309de2f09ffcf280818b0a2c7897a4f300005ddd 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -76,41 +76,37 @@ init_data_merge(int npar, gmx_ana_selparam_t *param);
  * \returns   0 if everything is successful, -1 on error.
  */
 static void
-init_merge(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+init_merge(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
 /** Initializes output for the \p merge selection modifier. */
 static void
-init_output_merge(t_topology *top, gmx_ana_selvalue_t *out, void *data);
+init_output_merge(const gmx_mtop_t *top, gmx_ana_selvalue_t *out, void *data);
 /** Initializes output for the \p plus selection modifier. */
 static void
-init_output_plus(t_topology *top, gmx_ana_selvalue_t *out, void *data);
+init_output_plus(const gmx_mtop_t *top, gmx_ana_selvalue_t *out, void *data);
 /** Frees the memory allocated for the merging selection modifiers. */
 static void
 free_data_merge(void *data);
 /*! \brief
  * Evaluates the \p merge selection modifier.
  *
- * \param[in]  top   Not used.
- * \param[in]  fr    Not used.
- * \param[in]  pbc   Not used.
+ * \param[in]  context Not used.
  * \param[in]  p     Positions to merge (should point to \p data->p1).
  * \param[out] out   Output data structure (\p out->u.p is used).
  * \param[in]  data  Should point to a \p t_methoddata_merge.
  */
 static void
-evaluate_merge(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_merge(const gmx::SelMethodEvalContext &context,
                gmx_ana_pos_t * p, gmx_ana_selvalue_t *out, void *data);
 /*! \brief
  * Evaluates the \p plus selection modifier.
  *
- * \param[in]  top   Not used.
- * \param[in]  fr    Not used.
- * \param[in]  pbc   Not used.
+ * \param[in]  context Not used.
  * \param[in]  p     Positions to merge (should point to \p data->p1).
  * \param[out] out   Output data structure (\p out->u.p is used).
  * \param[in]  data  Should point to a \p t_methoddata_merge.
  */
 static void
-evaluate_plus(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_plus(const gmx::SelMethodEvalContext &context,
               gmx_ana_pos_t * p, gmx_ana_selvalue_t *out, void *data);
 
 /** Parameters for the merging selection modifiers. */
@@ -201,7 +197,7 @@ init_data_merge(int npar, gmx_ana_selparam_t *param)
 }
 
 static void
-init_merge(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t * /* param */, void *data)
+init_merge(const gmx_mtop_t * /* top */, int /* npar */, gmx_ana_selparam_t * /* param */, void *data)
 {
     t_methoddata_merge *d = (t_methoddata_merge *)data;
 
@@ -228,7 +224,7 @@ init_merge(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t * /* param
  * \param[in,out] data  Should point to \c t_methoddata_merge.
  */
 static void
-init_output_common(t_topology *top, gmx_ana_selvalue_t *out, void *data)
+init_output_common(const gmx_mtop_t *top, gmx_ana_selvalue_t *out, void *data)
 {
     t_methoddata_merge *d = (t_methoddata_merge *)data;
 
@@ -254,7 +250,7 @@ init_output_common(t_topology *top, gmx_ana_selvalue_t *out, void *data)
  * \param[in,out] data  Should point to \c t_methoddata_merge.
  */
 static void
-init_output_merge(t_topology *top, gmx_ana_selvalue_t *out, void *data)
+init_output_merge(const gmx_mtop_t *top, gmx_ana_selvalue_t *out, void *data)
 {
     t_methoddata_merge *d = (t_methoddata_merge *)data;
     int                 i, j;
@@ -276,7 +272,7 @@ init_output_merge(t_topology *top, gmx_ana_selvalue_t *out, void *data)
  * \param[in,out] data  Should point to \c t_methoddata_merge.
  */
 static void
-init_output_plus(t_topology *top, gmx_ana_selvalue_t *out, void *data)
+init_output_plus(const gmx_mtop_t *top, gmx_ana_selvalue_t *out, void *data)
 {
     t_methoddata_merge *d = (t_methoddata_merge *)data;
     int                 i;
@@ -305,7 +301,7 @@ free_data_merge(void *data)
 }
 
 static void
-evaluate_merge(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_merge(const gmx::SelMethodEvalContext & /*context*/,
                gmx_ana_pos_t * /* p */, gmx_ana_selvalue_t *out, void *data)
 {
     t_methoddata_merge *d = (t_methoddata_merge *)data;
@@ -335,7 +331,7 @@ evaluate_merge(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
 }
 
 static void
-evaluate_plus(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_plus(const gmx::SelMethodEvalContext & /*context*/,
               gmx_ana_pos_t * /* p */, gmx_ana_selvalue_t *out, void *data)
 {
     t_methoddata_merge *d = (t_methoddata_merge *)data;
index 5ca87fc698b4cfa1461236451567ec486111a687..b55c4048bafaa1189cc0cc13fdc6f748d58ef5da 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -87,7 +87,7 @@ init_data_permute(int npar, gmx_ana_selparam_t *param);
  * \returns   0 if the input permutation is valid, -1 on error.
  */
 static void
-init_permute(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+init_permute(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
 /*! \brief
  * Initializes output for the \p permute selection modifier.
  *
@@ -96,26 +96,23 @@ init_permute(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
  * \param[in,out] data  Should point to \c t_methoddata_permute.
  */
 static void
-init_output_permute(t_topology *top, gmx_ana_selvalue_t *out, void *data);
+init_output_permute(const gmx_mtop_t *top, gmx_ana_selvalue_t *out, void *data);
 /** Frees the memory allocated for the \p permute selection modifier. */
 static void
 free_data_permute(void *data);
-static void
 /*! \brief
  * Evaluates the \p permute selection modifier.
  *
- * \param[in]  top   Not used.
- * \param[in]  fr    Not used.
- * \param[in]  pbc   Not used.
+ * \param[in]  context Not used.
  * \param[in]  p     Positions to permute (should point to \p data->p).
  * \param[out] out   Output data structure (\p out->u.p is used).
  * \param[in]  data  Should point to a \p t_methoddata_permute.
- * \returns    0 if \p p could be permuted, -1 on error.
  *
- * Returns -1 if the size of \p p is not divisible by the number of
+ * Throws if the size of \p p is not divisible by the number of
  * elements in the permutation.
  */
-evaluate_permute(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+static void
+evaluate_permute(const gmx::SelMethodEvalContext &context,
                  gmx_ana_pos_t *p, gmx_ana_selvalue_t *out, void *data);
 
 /** Parameters for the \p permute selection modifier. */
@@ -171,7 +168,7 @@ init_data_permute(int /* npar */, gmx_ana_selparam_t *param)
 }
 
 static void
-init_permute(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
+init_permute(const gmx_mtop_t * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
 {
     t_methoddata_permute *d = (t_methoddata_permute *)data;
     int                   i;
@@ -204,7 +201,7 @@ init_permute(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param,
 }
 
 static void
-init_output_permute(t_topology * /* top */, gmx_ana_selvalue_t *out, void *data)
+init_output_permute(const gmx_mtop_t * /* top */, gmx_ana_selvalue_t *out, void *data)
 {
     t_methoddata_permute *d = (t_methoddata_permute *)data;
     int                   i, j, b;
@@ -238,7 +235,7 @@ free_data_permute(void *data)
 }
 
 static void
-evaluate_permute(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_permute(const gmx::SelMethodEvalContext & /*context*/,
                  gmx_ana_pos_t * /*p*/, gmx_ana_selvalue_t *out, void *data)
 {
     t_methoddata_permute *d = (t_methoddata_permute *)data;
index 2db9245eef3e5e89787be87fc2f379466358dbab..1b22204c83d95118042b7ee54a36271a94818bd1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -90,7 +90,7 @@ set_poscoll_pos(gmx::PositionCalculationCollection *pcc, void *data);
  * externally using _gmx_selelem_set_kwpos_type().
  */
 static void
-init_kwpos(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+init_kwpos(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
 /*! \brief
  * Initializes the \p cog selection method.
  *
@@ -101,7 +101,7 @@ init_kwpos(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
  * \returns       0 on success, a non-zero error code on error.
  */
 static void
-init_cog(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+init_cog(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
 /*! \brief
  * Initializes the \p cog selection method.
  *
@@ -112,7 +112,7 @@ init_cog(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
  * \returns       0 on success, a non-zero error code on error.
  */
 static void
-init_com(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+init_com(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
 /*! \brief
  * Initializes output for position evaluation selection methods.
  *
@@ -122,13 +122,14 @@ init_com(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
  * \returns       0 for success.
  */
 static void
-init_output_pos(t_topology *top, gmx_ana_selvalue_t *out, void *data);
+init_output_pos(const gmx_mtop_t *top, gmx_ana_selvalue_t *out, void *data);
 /** Frees the data allocated for position evaluation selection methods. */
 static void
 free_data_pos(void *data);
 /** Evaluates position evaluation selection methods. */
 static void
-evaluate_pos(t_topology * /* top */, t_trxframe *fr, t_pbc *pbc, gmx_ana_index_t * /* g */, gmx_ana_selvalue_t *out, void *data);
+evaluate_pos(const gmx::SelMethodEvalContext &context,
+             gmx_ana_index_t * /* g */, gmx_ana_selvalue_t *out, void *data);
 
 /** Parameters for position keyword evaluation. */
 static gmx_ana_selparam_t smparams_keyword_pos[] = {
@@ -173,7 +174,7 @@ gmx_ana_selmethod_t sm_cog = {
 
 /** Selection method data for the \p com method. */
 gmx_ana_selmethod_t sm_com = {
-    "com", POS_VALUE, SMETH_REQTOP | SMETH_DYNAMIC | SMETH_SINGLEVAL,
+    "com", POS_VALUE, SMETH_REQMASS | SMETH_DYNAMIC | SMETH_SINGLEVAL,
     asize(smparams_com), smparams_com,
     &init_data_pos,
     &set_poscoll_pos,
@@ -238,6 +239,29 @@ _gmx_selelem_is_default_kwpos(const gmx::SelectionTreeElement &sel)
     return d->type == NULL;
 }
 
+/*! \brief
+ * Updates selection method flags about required topology information.
+ *
+ * Sets the flags to require topology and/or masses if the position calculation
+ * requires them.
+ */
+static void set_pos_method_flags(gmx_ana_selmethod_t *method,
+                                 t_methoddata_pos    *d)
+{
+    const bool forces = (d->flags != -1 && (d->flags & POS_FORCES));
+    switch (gmx::PositionCalculationCollection::requiredTopologyInfoForType(d->type, forces))
+    {
+        case gmx::PositionCalculationCollection::RequiredTopologyInfo::TopologyAndMasses:
+            method->flags |= SMETH_REQMASS;
+        // fallthrough
+        case gmx::PositionCalculationCollection::RequiredTopologyInfo::Topology:
+            method->flags |= SMETH_REQTOP;
+            break;
+        case gmx::PositionCalculationCollection::RequiredTopologyInfo::None:
+            break;
+    }
+}
+
 /*!
  * \param[in,out] sel   Selection element to initialize.
  * \param[in]     type  One of the enum values acceptable for
@@ -259,12 +283,8 @@ _gmx_selelem_set_kwpos_type(gmx::SelectionTreeElement *sel, const char *type)
     }
     if (!d->type && type)
     {
-        d->type  = gmx_strdup(type);
-        /* FIXME: It would be better not to have the string here hardcoded. */
-        if (type[0] != 'a')
-        {
-            sel->u.expr.method->flags |= SMETH_REQTOP;
-        }
+        d->type = gmx_strdup(type);
+        set_pos_method_flags(sel->u.expr.method, d);
     }
 }
 
@@ -289,12 +309,15 @@ _gmx_selelem_set_kwpos_flags(gmx::SelectionTreeElement *sel, int flags)
     }
     if (d->flags == -1)
     {
+        GMX_RELEASE_ASSERT(d->type != nullptr,
+                           "Position type should be set before flags");
         d->flags = flags;
+        set_pos_method_flags(sel->u.expr.method, d);
     }
 }
 
 static void
-init_kwpos(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
+init_kwpos(const gmx_mtop_t * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
 {
     t_methoddata_pos *d = (t_methoddata_pos *)data;
 
@@ -311,7 +334,7 @@ init_kwpos(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, vo
 }
 
 static void
-init_cog(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
+init_cog(const gmx_mtop_t * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
 {
     t_methoddata_pos *d = (t_methoddata_pos *)data;
 
@@ -321,7 +344,7 @@ init_cog(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, void
 }
 
 static void
-init_com(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
+init_com(const gmx_mtop_t * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
 {
     t_methoddata_pos *d = (t_methoddata_pos *)data;
 
@@ -332,7 +355,7 @@ init_com(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, void
 }
 
 static void
-init_output_pos(t_topology * /* top */, gmx_ana_selvalue_t *out, void *data)
+init_output_pos(const gmx_mtop_t * /* top */, gmx_ana_selvalue_t *out, void *data)
 {
     t_methoddata_pos *d = (t_methoddata_pos *)data;
 
@@ -363,10 +386,10 @@ free_data_pos(void *data)
  * in \c t_methoddata_pos::g and stores the results in \p out->u.p.
  */
 static void
-evaluate_pos(t_topology * /* top */, t_trxframe *fr, t_pbc *pbc,
+evaluate_pos(const gmx::SelMethodEvalContext &context,
              gmx_ana_index_t * /* g */, gmx_ana_selvalue_t *out, void *data)
 {
     t_methoddata_pos *d = (t_methoddata_pos *)data;
 
-    gmx_ana_poscalc_update(d->pc, out->u.p, &d->g, fr, pbc);
+    gmx_ana_poscalc_update(d->pc, out->u.p, &d->g, context.fr, context.pbc);
 }
index 7c3c9c2c1594022bcbd6d4b35564fa4621c6a152..f475efd72d09eaed9626e4c4f840808d8d6e73c3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -119,43 +119,39 @@ init_data_same(int npar, gmx_ana_selparam_t *param);
  * \returns 0 on success, -1 on failure.
  */
 static void
-init_same(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+init_same(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
 /** Frees the data allocated for the \p same selection method. */
 static void
 free_data_same(void *data);
 /*! \brief
  * Initializes the evaluation of the \p same selection method for a frame.
  *
- * \param[in]  top  Not used.
- * \param[in]  fr   Current frame.
- * \param[in]  pbc  PBC structure.
+ * \param[in]  context  Not used.
  * \param      data Should point to a \ref t_methoddata_same.
  *
  * Sorts the \c data->as.i array and removes identical values for faster and
  * simpler lookup.
  */
 static void
-init_frame_same_int(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data);
+init_frame_same_int(const gmx::SelMethodEvalContext &context, void *data);
 /** Evaluates the \p same selection method. */
 static void
-evaluate_same_int(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_same_int(const gmx::SelMethodEvalContext &context,
                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
 /*! \brief
  * Initializes the evaluation of the \p same selection method for a frame.
  *
- * \param[in]  top  Not used.
- * \param[in]  fr   Current frame.
- * \param[in]  pbc  PBC structure.
+ * \param[in]  context  Not used.
  * \param      data Should point to a \ref t_methoddata_same.
  *
  * Sorts the \c data->as.s array and removes identical values for faster and
  * simpler lookup.
  */
 static void
-init_frame_same_str(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data);
+init_frame_same_str(const gmx::SelMethodEvalContext &context, void *data);
 /** Evaluates the \p same selection method. */
 static void
-evaluate_same_str(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_same_str(const gmx::SelMethodEvalContext &context,
                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
 
 /** Parameters for the \p same selection method. */
@@ -285,7 +281,7 @@ _gmx_selelem_custom_init_same(gmx_ana_selmethod_t                           **me
 }
 
 static void
-init_same(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
+init_same(const gmx_mtop_t * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
 {
     t_methoddata_same *d = (t_methoddata_same *)data;
 
@@ -333,7 +329,7 @@ cmp_int(const void *a, const void *b)
 }
 
 static void
-init_frame_same_int(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */, void *data)
+init_frame_same_int(const gmx::SelMethodEvalContext & /*context*/, void *data)
 {
     t_methoddata_same *d = (t_methoddata_same *)data;
     int                i, j;
@@ -385,7 +381,7 @@ init_frame_same_int(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pb
  * \c data->val.
  */
 static void
-evaluate_same_int(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_same_int(const gmx::SelMethodEvalContext & /*context*/,
                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
 {
     t_methoddata_same     *d = (t_methoddata_same *)data;
@@ -461,7 +457,7 @@ cmp_str(const void *a, const void *b)
 }
 
 static void
-init_frame_same_str(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */, void *data)
+init_frame_same_str(const gmx::SelMethodEvalContext & /*context*/, void *data)
 {
     t_methoddata_same *d = (t_methoddata_same *)data;
     int                i, j;
@@ -508,7 +504,7 @@ init_frame_same_str(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pb
  * \c data->val.
  */
 static void
-evaluate_same_str(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_same_str(const gmx::SelMethodEvalContext & /*context*/,
                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
 {
     t_methoddata_same     *d = (t_methoddata_same *)data;
index ca384efd8144d882ea083bb9dadc4c7f08bf3733..60910d1cbe43b604284636459c9c68f22b22d41b 100644 (file)
 #include <cctype>
 
 #include "gromacs/selection/position.h"
+#include "gromacs/topology/mtop_lookup.h"
 #include "gromacs/topology/topology.h"
 #include "gromacs/utility/arraysize.h"
 #include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/gmxassert.h"
 
 #include "selmethod.h"
 
 /** Evaluates the \p all selection keyword. */
 static void
-evaluate_all(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_all(const gmx::SelMethodEvalContext &context,
              gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
 /** Evaluates the \p none selection keyword. */
 static void
-evaluate_none(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_none(const gmx::SelMethodEvalContext &context,
               gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
 /** Evaluates the \p atomnr selection keyword. */
 static void
-evaluate_atomnr(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_atomnr(const gmx::SelMethodEvalContext &context,
                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
 /** Evaluates the \p resnr selection keyword. */
 static void
-evaluate_resnr(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_resnr(const gmx::SelMethodEvalContext &context,
                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
 /** Evaluates the \p resindex selection keyword. */
 static void
-evaluate_resindex(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_resindex(const gmx::SelMethodEvalContext &context,
                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
 /*! \brief
  * Checks whether molecule information is present in the topology.
@@ -82,18 +84,18 @@ evaluate_resindex(t_topology *top, t_trxframe *fr, t_pbc *pbc,
  * If molecule information is not found, also prints an error message.
  */
 static void
-check_molecules(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+check_molecules(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
 /** Evaluates the \p molindex selection keyword. */
 static void
-evaluate_molindex(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_molindex(const gmx::SelMethodEvalContext &context,
                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
 /** Evaluates the \p atomname selection keyword. */
 static void
-evaluate_atomname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_atomname(const gmx::SelMethodEvalContext &context,
                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
 /** Evaluates the \p pdbatomname selection keyword. */
 static void
-evaluate_pdbatomname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_pdbatomname(const gmx::SelMethodEvalContext &context,
                      gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
 /*! \brief
  * Checks whether atom types are present in the topology.
@@ -102,31 +104,38 @@ evaluate_pdbatomname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
  * \param     npar Not used.
  * \param     param Not used.
  * \param     data Not used.
- * \returns   0 if atom types are present in the topology, -1 otherwise.
- *
- * If the atom types are not found, also prints an error message.
  */
 static void
-check_atomtype(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+check_atomtype(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
 /** Evaluates the \p atomtype selection keyword. */
 static void
-evaluate_atomtype(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_atomtype(const gmx::SelMethodEvalContext &context,
                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
 /** Evaluates the \p insertcode selection keyword. */
 static void
-evaluate_insertcode(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_insertcode(const gmx::SelMethodEvalContext &context,
                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
 /** Evaluates the \p chain selection keyword. */
 static void
-evaluate_chain(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_chain(const gmx::SelMethodEvalContext &context,
                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
 /** Evaluates the \p mass selection keyword. */
 static void
-evaluate_mass(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_mass(const gmx::SelMethodEvalContext &context,
               gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+/*! \brief
+ * Checks whether charges are present in the topology.
+ *
+ * \param[in] top  Topology structure.
+ * \param     npar Not used.
+ * \param     param Not used.
+ * \param     data Not used.
+ */
+static void
+check_charge(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
 /** Evaluates the \p charge selection keyword. */
 static void
-evaluate_charge(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_charge(const gmx::SelMethodEvalContext &context,
                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
 /*! \brief
  * Checks whether PDB info is present in the topology.
@@ -140,35 +149,35 @@ evaluate_charge(t_topology *top, t_trxframe *fr, t_pbc *pbc,
  * If PDB info is not found, also prints an error message.
  */
 static void
-check_pdbinfo(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+check_pdbinfo(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
 /** Evaluates the \p altloc selection keyword. */
 static void
-evaluate_altloc(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_altloc(const gmx::SelMethodEvalContext &context,
                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
 /** Evaluates the \p occupancy selection keyword. */
 static void
-evaluate_occupancy(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_occupancy(const gmx::SelMethodEvalContext &context,
                    gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
 /** Evaluates the \p betafactor selection keyword. */
 static void
-evaluate_betafactor(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_betafactor(const gmx::SelMethodEvalContext &context,
                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
 /** Evaluates the \p resname selection keyword. */
 static void
-evaluate_resname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_resname(const gmx::SelMethodEvalContext &context,
                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
 
 /** Evaluates the \p x selection keyword. */
 static void
-evaluate_x(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_x(const gmx::SelMethodEvalContext &context,
            gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
 /** Evaluates the \p y selection keyword. */
 static void
-evaluate_y(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_y(const gmx::SelMethodEvalContext &context,
            gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
 /** Evaluates the \p z selection keyword. */
 static void
-evaluate_z(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_z(const gmx::SelMethodEvalContext &context,
            gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
 
 //! Help title for atom name selection keywords.
@@ -392,7 +401,7 @@ gmx_ana_selmethod_t sm_chain = {
 
 /** Selection method data for \p mass selection keyword. */
 gmx_ana_selmethod_t sm_mass = {
-    "mass", REAL_VALUE, SMETH_REQTOP,
+    "mass", REAL_VALUE, SMETH_REQMASS,
     0, NULL,
     NULL,
     NULL,
@@ -410,7 +419,7 @@ gmx_ana_selmethod_t sm_charge = {
     0, NULL,
     NULL,
     NULL,
-    NULL,
+    &check_charge,
     NULL,
     NULL,
     NULL,
@@ -509,7 +518,7 @@ gmx_ana_selmethod_t sm_z = {
  * Copies \p g to \p out->u.g.
  */
 static void
-evaluate_all(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_all(const gmx::SelMethodEvalContext & /*context*/,
              gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
 {
     gmx_ana_index_copy(out->u.g, g, false);
@@ -522,7 +531,7 @@ evaluate_all(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
  * Returns an empty \p out->u.g.
  */
 static void
-evaluate_none(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_none(const gmx::SelMethodEvalContext & /*context*/,
               gmx_ana_index_t * /* g */, gmx_ana_selvalue_t *out, void * /* data */)
 {
     out->u.g->isize = 0;
@@ -535,7 +544,7 @@ evaluate_none(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
  * Returns the indices for each atom in \p out->u.i.
  */
 static void
-evaluate_atomnr(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_atomnr(const gmx::SelMethodEvalContext & /*context*/,
                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
 {
     int  i;
@@ -554,17 +563,15 @@ evaluate_atomnr(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */
  * Returns the residue numbers for each atom in \p out->u.i.
  */
 static void
-evaluate_resnr(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_resnr(const gmx::SelMethodEvalContext &context,
                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
 {
-    int  i;
-    int  resind;
-
-    out->nr = g->isize;
-    for (i = 0; i < g->isize; ++i)
+    out->nr  = g->isize;
+    int molb = 0;
+    for (int i = 0; i < g->isize; ++i)
     {
-        resind      = top->atoms.atom[g->index[i]].resind;
-        out->u.i[i] = top->atoms.resinfo[resind].nr;
+        mtopGetAtomAndResidueName(context.top, g->index[i], &molb,
+                                  nullptr, &out->u.i[i], nullptr, nullptr);
     }
 }
 
@@ -575,20 +582,22 @@ evaluate_resnr(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
  * Returns the residue indices for each atom in \p out->u.i.
  */
 static void
-evaluate_resindex(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_resindex(const gmx::SelMethodEvalContext &context,
                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
 {
-    int  i;
-
-    out->nr = g->isize;
-    for (i = 0; i < g->isize; ++i)
+    out->nr  = g->isize;
+    int molb = 0;
+    for (int i = 0; i < g->isize; ++i)
     {
-        out->u.i[i] = top->atoms.atom[g->index[i]].resind + 1;
+        int resind;
+        mtopGetAtomAndResidueName(context.top, g->index[i], &molb,
+                                  nullptr, nullptr, nullptr, &resind);
+        out->u.i[i] = resind + 1;
     }
 }
 
 static void
-check_molecules(t_topology *top, int /* npar */, gmx_ana_selparam_t * /* param */, void * /* data */)
+check_molecules(const gmx_mtop_t *top, int /* npar */, gmx_ana_selparam_t * /* param */, void * /* data */)
 {
     bool bOk;
 
@@ -606,7 +615,7 @@ check_molecules(t_topology *top, int /* npar */, gmx_ana_selparam_t * /* param *
  * Returns the molecule indices for each atom in \p out->u.i.
  */
 static void
-evaluate_molindex(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_molindex(const gmx::SelMethodEvalContext &context,
                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
 {
     int  i, j;
@@ -614,7 +623,7 @@ evaluate_molindex(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
     out->nr = g->isize;
     for (i = j = 0; i < g->isize; ++i)
     {
-        while (top->mols.index[j + 1] <= g->index[i])
+        while (context.top->mols.index[j + 1] <= g->index[i])
         {
             ++j;
         }
@@ -629,15 +638,17 @@ evaluate_molindex(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
  * Returns the atom name for each atom in \p out->u.s.
  */
 static void
-evaluate_atomname(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_atomname(const gmx::SelMethodEvalContext &context,
                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
 {
-    int  i;
-
     out->nr = g->isize;
-    for (i = 0; i < g->isize; ++i)
+    int molb = 0;
+    for (int i = 0; i < g->isize; ++i)
     {
-        out->u.s[i] = *top->atoms.atomname[g->index[i]];
+        const char *atom_name;
+        mtopGetAtomAndResidueName(context.top, g->index[i], &molb,
+                                  &atom_name, nullptr, nullptr, nullptr);
+        out->u.s[i] = const_cast<char *>(atom_name);
     }
 }
 
@@ -648,30 +659,26 @@ evaluate_atomname(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
  * Returns the PDB atom name for each atom in \p out->u.s.
  */
 static void
-evaluate_pdbatomname(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_pdbatomname(const gmx::SelMethodEvalContext &context,
                      gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
 {
-    int  i;
-
     out->nr = g->isize;
-    for (i = 0; i < g->isize; ++i)
+    int molb = 0;
+    for (int i = 0; i < g->isize; ++i)
     {
-        char *s = top->atoms.pdbinfo[g->index[i]].atomnm;
+        const char *s = mtopGetAtomPdbInfo(context.top, g->index[i], &molb).atomnm;
         while (std::isspace(*s))
         {
             ++s;
         }
-        out->u.s[i] = s;
+        out->u.s[i] = const_cast<char *>(s);
     }
 }
 
 static void
-check_atomtype(t_topology *top, int /* npar */, gmx_ana_selparam_t * /* param */, void * /* data */)
+check_atomtype(const gmx_mtop_t *top, int /* npar */, gmx_ana_selparam_t * /* param */, void * /* data */)
 {
-    bool bOk;
-
-    bOk = (top != NULL && top->atoms.atomtype != NULL);
-    if (!bOk)
+    if (!gmx_mtop_has_atomtypes(top))
     {
         GMX_THROW(gmx::InconsistentInputError("Atom types not available in topology"));
     }
@@ -685,15 +692,18 @@ check_atomtype(t_topology *top, int /* npar */, gmx_ana_selparam_t * /* param */
  * Segfaults if atom types are not found in the topology.
  */
 static void
-evaluate_atomtype(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_atomtype(const gmx::SelMethodEvalContext &context,
                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
 {
-    int  i;
-
     out->nr = g->isize;
-    for (i = 0; i < g->isize; ++i)
+    int molb = 0;
+    for (int i = 0; i < g->isize; ++i)
     {
-        out->u.s[i] = *top->atoms.atomtype[g->index[i]];
+        int atomIndexInMolecule;
+        mtopGetMolblockIndex(context.top, g->index[i], &molb,
+                             nullptr, &atomIndexInMolecule);
+        const gmx_moltype_t &moltype = context.top->moltype[context.top->molblock[molb].type];
+        out->u.s[i] = *moltype.atoms.atomtype[atomIndexInMolecule];
     }
 }
 
@@ -704,17 +714,14 @@ evaluate_atomtype(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
  * Returns the residue name for each atom in \p out->u.s.
  */
 static void
-evaluate_resname(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_resname(const gmx::SelMethodEvalContext &context,
                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
 {
-    int  i;
-    int  resind;
-
     out->nr = g->isize;
-    for (i = 0; i < g->isize; ++i)
+    int molb = 0;
+    for (int i = 0; i < g->isize; ++i)
     {
-        resind      = top->atoms.atom[g->index[i]].resind;
-        out->u.s[i] = *top->atoms.resinfo[resind].name;
+        out->u.s[i] = *mtopGetResidueInfo(context.top, g->index[i], &molb).name;
     }
 }
 
@@ -725,17 +732,14 @@ evaluate_resname(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
  * Returns the insertion code for each atom in \p out->u.s.
  */
 static void
-evaluate_insertcode(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_insertcode(const gmx::SelMethodEvalContext &context,
                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
 {
-    int  i;
-    int  resind;
-
     out->nr = g->isize;
-    for (i = 0; i < g->isize; ++i)
+    int molb = 0;
+    for (int i = 0; i < g->isize; ++i)
     {
-        resind         = top->atoms.atom[g->index[i]].resind;
-        out->u.s[i][0] = top->atoms.resinfo[resind].ic;
+        out->u.s[i][0] = mtopGetResidueInfo(context.top, g->index[i], &molb).ic;
     }
 }
 
@@ -746,17 +750,14 @@ evaluate_insertcode(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
  * Returns the chain for each atom in \p out->u.s.
  */
 static void
-evaluate_chain(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_chain(const gmx::SelMethodEvalContext &context,
                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
 {
-    int  i;
-    int  resind;
-
     out->nr = g->isize;
-    for (i = 0; i < g->isize; ++i)
+    int molb = 0;
+    for (int i = 0; i < g->isize; ++i)
     {
-        resind         = top->atoms.atom[g->index[i]].resind;
-        out->u.s[i][0] = top->atoms.resinfo[resind].chainid;
+        out->u.s[i][0] = mtopGetResidueInfo(context.top, g->index[i], &molb).chainid;
     }
 }
 
@@ -767,15 +768,26 @@ evaluate_chain(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
  * Returns the mass for each atom in \p out->u.r.
  */
 static void
-evaluate_mass(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_mass(const gmx::SelMethodEvalContext &context,
               gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
 {
-    int  i;
-
+    GMX_RELEASE_ASSERT(gmx_mtop_has_masses(context.top),
+                       "Masses not available for evaluation");
     out->nr = g->isize;
-    for (i = 0; i < g->isize; ++i)
+    int molb = 0;
+    for (int i = 0; i < g->isize; ++i)
+    {
+        out->u.r[i] = mtopGetAtomMass(context.top, g->index[i], &molb);
+    }
+}
+
+
+static void
+check_charge(const gmx_mtop_t *top, int /* npar */, gmx_ana_selparam_t * /* param */, void * /* data */)
+{
+    if (!gmx_mtop_has_charges(top))
     {
-        out->u.r[i] = top->atoms.atom[g->index[i]].m;
+        GMX_THROW(gmx::InconsistentInputError("Charges not available in topology"));
     }
 }
 
@@ -786,25 +798,21 @@ evaluate_mass(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
  * Returns the charge for each atom in \p out->u.r.
  */
 static void
-evaluate_charge(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_charge(const gmx::SelMethodEvalContext &context,
                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
 {
-    int  i;
-
     out->nr = g->isize;
-    for (i = 0; i < g->isize; ++i)
+    int molb = 0;
+    for (int i = 0; i < g->isize; ++i)
     {
-        out->u.r[i] = top->atoms.atom[g->index[i]].q;
+        out->u.r[i] = mtopGetAtomParameters(context.top, g->index[i], &molb).q;
     }
 }
 
 static void
-check_pdbinfo(t_topology *top, int /* npar */, gmx_ana_selparam_t * /* param */, void * /* data */)
+check_pdbinfo(const gmx_mtop_t *top, int /* npar */, gmx_ana_selparam_t * /* param */, void * /* data */)
 {
-    bool bOk;
-
-    bOk = (top != NULL && top->atoms.pdbinfo != NULL);
-    if (!bOk)
+    if (!gmx_mtop_has_pdbinfo(top))
     {
         GMX_THROW(gmx::InconsistentInputError("PDB info not available in topology"));
     }
@@ -817,15 +825,14 @@ check_pdbinfo(t_topology *top, int /* npar */, gmx_ana_selparam_t * /* param */,
  * Returns the alternate location identifier for each atom in \p out->u.s.
  */
 static void
-evaluate_altloc(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_altloc(const gmx::SelMethodEvalContext &context,
                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
 {
-    int  i;
-
     out->nr = g->isize;
-    for (i = 0; i < g->isize; ++i)
+    int molb = 0;
+    for (int i = 0; i < g->isize; ++i)
     {
-        out->u.s[i][0] = top->atoms.pdbinfo[g->index[i]].altloc;
+        out->u.s[i][0] = mtopGetAtomPdbInfo(context.top, g->index[i], &molb).altloc;
     }
 }
 
@@ -837,15 +844,14 @@ evaluate_altloc(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
  * Segfaults if PDB info is not found in the topology.
  */
 static void
-evaluate_occupancy(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_occupancy(const gmx::SelMethodEvalContext &context,
                    gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
 {
-    int  i;
-
     out->nr = g->isize;
-    for (i = 0; i < g->isize; ++i)
+    int molb = 0;
+    for (int i = 0; i < g->isize; ++i)
     {
-        out->u.r[i] = top->atoms.pdbinfo[g->index[i]].occup;
+        out->u.r[i] = mtopGetAtomPdbInfo(context.top, g->index[i], &molb).occup;
     }
 }
 
@@ -857,15 +863,14 @@ evaluate_occupancy(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
  * Segfaults if PDB info is not found in the topology.
  */
 static void
-evaluate_betafactor(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_betafactor(const gmx::SelMethodEvalContext &context,
                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
 {
-    int  i;
-
     out->nr = g->isize;
-    for (i = 0; i < g->isize; ++i)
+    int molb = 0;
+    for (int i = 0; i < g->isize; ++i)
     {
-        out->u.r[i] = top->atoms.pdbinfo[g->index[i]].bfac;
+        out->u.r[i] = mtopGetAtomPdbInfo(context.top, g->index[i], &molb).bfac;
     }
 }
 
@@ -898,7 +903,7 @@ evaluate_coord(real out[], gmx_ana_pos_t *pos, int d)
  * Returns the \p x coordinate for each position in \p out->u.r.
  */
 static void
-evaluate_x(t_topology * /*top*/, t_trxframe * /*fr*/, t_pbc * /*pbc*/,
+evaluate_x(const gmx::SelMethodEvalContext & /*context*/,
            gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void * /*data*/)
 {
     out->nr = pos->count();
@@ -912,7 +917,7 @@ evaluate_x(t_topology * /*top*/, t_trxframe * /*fr*/, t_pbc * /*pbc*/,
  * Returns the \p y coordinate for each position in \p out->u.r.
  */
 static void
-evaluate_y(t_topology * /*top*/, t_trxframe * /*fr*/, t_pbc * /*pbc*/,
+evaluate_y(const gmx::SelMethodEvalContext & /*context*/,
            gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void * /*data*/)
 {
     out->nr = pos->count();
@@ -926,7 +931,7 @@ evaluate_y(t_topology * /*top*/, t_trxframe * /*fr*/, t_pbc * /*pbc*/,
  * Returns the \p z coordinate for each position in \p out->u.r.
  */
 static void
-evaluate_z(t_topology * /*top*/, t_trxframe * /*fr*/, t_pbc * /*pbc*/,
+evaluate_z(const gmx::SelMethodEvalContext & /*context*/,
            gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void * /*data*/)
 {
     out->nr = pos->count();
index ffd884fe591837cbd5bdaa4c1b4bbe302dabfff2..70bb817208ea4a62f32df42baec8319f16338b29 100644 (file)
@@ -296,7 +296,7 @@ TEST_F(IndexBlockTest, ChecksGroupForCompleteResiduesPositive)
 
     topManager_.initAtoms(15);
     topManager_.initUniformResidues(3);
-    t_topology *top = topManager_.topology();
+    gmx_mtop_t *top = topManager_.topology();
 
     setGroup(group1);
     EXPECT_TRUE(gmx_ana_index_has_complete_elems(&g_, INDEX_RES, top));
@@ -310,10 +310,11 @@ TEST_F(IndexBlockTest, ChecksGroupForCompleteResiduesNegative)
     const int group1[] = { 3, 4, 5, 6, 7, 8, 12, 13 };
     const int group2[] = { 3, 4, 5, 6, 7, 12, 13, 14 };
     const int group3[] = { 4, 5, 6, 7, 8, 12, 13, 14 };
+    const int group4[] = { 3, 4, 5, 6, 8, 12, 13, 14 };
 
     topManager_.initAtoms(18);
     topManager_.initUniformResidues(3);
-    t_topology *top = topManager_.topology();
+    gmx_mtop_t *top = topManager_.topology();
 
     setGroup(group1);
     EXPECT_FALSE(gmx_ana_index_has_complete_elems(&g_, INDEX_RES, top));
@@ -323,6 +324,9 @@ TEST_F(IndexBlockTest, ChecksGroupForCompleteResiduesNegative)
 
     setGroup(group3);
     EXPECT_FALSE(gmx_ana_index_has_complete_elems(&g_, INDEX_RES, top));
+
+    setGroup(group4);
+    EXPECT_FALSE(gmx_ana_index_has_complete_elems(&g_, INDEX_RES, top));
 }
 
 TEST_F(IndexBlockTest, ChecksGroupForCompleteMoleculesPositive)
@@ -331,7 +335,7 @@ TEST_F(IndexBlockTest, ChecksGroupForCompleteMoleculesPositive)
 
     topManager_.initAtoms(15);
     topManager_.initUniformMolecules(3);
-    t_topology *top = topManager_.topology();
+    gmx_mtop_t *top = topManager_.topology();
 
     setGroup(group);
     EXPECT_TRUE(gmx_ana_index_has_complete_elems(&g_, INDEX_MOL, top));
@@ -345,7 +349,7 @@ TEST_F(IndexBlockTest, ChecksGroupForCompleteMoleculesNegative)
 
     topManager_.initAtoms(18);
     topManager_.initUniformMolecules(3);
-    t_topology *top = topManager_.topology();
+    gmx_mtop_t *top = topManager_.topology();
 
     setGroup(group1);
     EXPECT_FALSE(gmx_ana_index_has_complete_elems(&g_, INDEX_MOL, top));
index 9cc30ecb704428cff573d13c3934d071ed269631..240f282ead94cd6920d8c7cdea50ae3e6ce4894b 100644 (file)
@@ -132,7 +132,7 @@ class NeighborhoodSearchTestData
                 testPos_.reserve(testPositions_.size());
                 for (size_t i = 0; i < testPositions_.size(); ++i)
                 {
-                    testPos_.push_back(testPositions_[i].x);
+                    testPos_.emplace_back(testPositions_[i].x);
                 }
             }
             return gmx::AnalysisNeighborhoodPositions(testPos_);
@@ -146,7 +146,7 @@ class NeighborhoodSearchTestData
         {
             GMX_RELEASE_ASSERT(testPos_.empty(),
                                "Cannot add positions after testPositions() call");
-            testPositions_.push_back(TestPosition(x));
+            testPositions_.emplace_back(x);
         }
         gmx::RVec generateRandomPosition();
         std::vector<int> generateIndex(int count, gmx_uint64_t seed) const;
index c9ed4c7f9418fbdc09019c7a5111649bb4789cb7..4b28450eea924596a469e5ab55da3fc359b70f67 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -157,12 +157,12 @@ PositionCalculationTest::~PositionCalculationTest()
 
 void PositionCalculationTest::generateCoordinates()
 {
-    t_topology *top   = topManager_.topology();
+    t_atoms    &atoms = topManager_.atoms();
     t_trxframe *frame = topManager_.frame();
-    for (int i = 0; i < top->atoms.nr; ++i)
+    for (int i = 0; i < atoms.nr; ++i)
     {
         frame->x[i][XX] = i;
-        frame->x[i][YY] = top->atoms.atom[i].resind;
+        frame->x[i][YY] = atoms.atom[i].resind;
         frame->x[i][ZZ] = 0.0;
         if (frame->bV)
         {
@@ -201,7 +201,7 @@ PositionCalculationTest::initPositions(gmx_ana_poscalc_t *pc, const char *name)
     posList_.reserve(posList_.size() + 1);
     PositionPointer p(new gmx_ana_pos_t());
     gmx_ana_pos_t  *result = p.get();
-    posList_.push_back(PositionTest(std::move(p), pc, name));
+    posList_.emplace_back(std::move(p), pc, name);
     gmx_ana_poscalc_init_pos(pc, result);
     return result;
 }
@@ -243,7 +243,10 @@ void PositionCalculationTest::testSingleStatic(
         flags |= POS_FORCES;
     }
     gmx_ana_poscalc_t *pc = createCalculation(type, flags);
-    EXPECT_EQ(bExpectTop, gmx_ana_poscalc_requires_top(pc));
+    const bool         requiresTopology
+        = gmx_ana_poscalc_required_topology_info(pc)
+            != gmx::PositionCalculationCollection::RequiredTopologyInfo::None;
+    EXPECT_EQ(bExpectTop, requiresTopology);
     setMaximumGroup(pc, atoms);
     gmx_ana_pos_t *p = initPositions(pc, NULL);
     checkInitialized();
@@ -268,7 +271,10 @@ void PositionCalculationTest::testSingleDynamic(
         const gmx::ConstArrayRef<int> &index)
 {
     gmx_ana_poscalc_t *pc = createCalculation(type, flags | POS_DYNAMIC);
-    EXPECT_EQ(bExpectTop, gmx_ana_poscalc_requires_top(pc));
+    const bool         requiresTopology
+        = gmx_ana_poscalc_required_topology_info(pc)
+            != gmx::PositionCalculationCollection::RequiredTopologyInfo::None;
+    EXPECT_EQ(bExpectTop, requiresTopology);
     setMaximumGroup(pc, initAtoms);
     gmx_ana_pos_t *p = initPositions(pc, NULL);
     checkInitialized();
@@ -295,7 +301,10 @@ void PositionCalculationTest::setTopologyIfRequired()
     std::vector<gmx_ana_poscalc_t *>::const_iterator pci;
     for (pci = pcList_.begin(); pci != pcList_.end(); ++pci)
     {
-        if (gmx_ana_poscalc_requires_top(*pci))
+        const bool         requiresTopology
+            = gmx_ana_poscalc_required_topology_info(*pci)
+                != gmx::PositionCalculationCollection::RequiredTopologyInfo::None;
+        if (requiresTopology)
         {
             bTopSet_ = true;
             pcc_.setTopology(topManager_.topology());
index 34f59aabcdd32885d0c449e4861232fde402de6d..c8c3a75c4a63151845f1ba538f8bc78e86e75bad 100644 (file)
@@ -91,7 +91,6 @@ class SelectionCollectionTest : public ::testing::Test
         gmx::test::TopologyManager  topManager_;
         gmx::SelectionCollection    sc_;
         gmx::SelectionList          sel_;
-        t_topology                 *top_;
         gmx_ana_indexgrps_t        *grps_;
 };
 
@@ -108,7 +107,7 @@ GMX_TEST_OPTIONS(SelectionCollectionTestOptions, options)
 #endif
 
 SelectionCollectionTest::SelectionCollectionTest()
-    : top_(NULL), grps_(NULL)
+    : grps_(NULL)
 {
     topManager_.requestFrame();
     sc_.setDebugLevel(s_debugLevel);
@@ -134,9 +133,7 @@ SelectionCollectionTest::loadTopology(const char *filename)
 void
 SelectionCollectionTest::setTopology()
 {
-    top_   = topManager_.topology();
-
-    ASSERT_NO_THROW_GMX(sc_.setTopology(top_, -1));
+    ASSERT_NO_THROW_GMX(sc_.setTopology(topManager_.topology(), -1));
 }
 
 void
@@ -423,26 +420,58 @@ SelectionCollectionDataTest::runTest(
 
 TEST_F(SelectionCollectionTest, HandlesNoSelections)
 {
-    EXPECT_FALSE(sc_.requiresTopology());
+    EXPECT_FALSE(sc_.requiredTopologyProperties().hasAny());
     EXPECT_NO_THROW_GMX(sc_.compile());
+    EXPECT_FALSE(sc_.requiredTopologyProperties().hasAny());
+}
+
+TEST_F(SelectionCollectionTest, HandlesNoSelectionsWithDefaultPositionType)
+{
+    EXPECT_NO_THROW_GMX(sc_.setOutputPosType("res_com"));
+    EXPECT_TRUE(sc_.requiredTopologyProperties().needsTopology);
+    EXPECT_TRUE(sc_.requiredTopologyProperties().needsMasses);
+    EXPECT_NO_THROW_GMX(sc_.setOutputPosType("res_cog"));
+    EXPECT_TRUE(sc_.requiredTopologyProperties().needsTopology);
+    EXPECT_FALSE(sc_.requiredTopologyProperties().needsMasses);
+    ASSERT_NO_THROW_GMX(sc_.parseFromString("atom of atomnr 1 to 10"));
+    ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
+    ASSERT_NO_THROW_GMX(sc_.compile());
+    EXPECT_FALSE(sc_.requiredTopologyProperties().hasAny());
 }
 
 TEST_F(SelectionCollectionTest, HandlesVelocityAndForceRequests)
 {
     ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromString("atomnr 1 to 10; none"));
+    EXPECT_FALSE(sc_.requiredTopologyProperties().hasAny());
     ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
     ASSERT_EQ(2U, sel_.size());
     ASSERT_NO_THROW_GMX(sel_[0].setEvaluateVelocities(true));
     ASSERT_NO_THROW_GMX(sel_[1].setEvaluateVelocities(true));
     ASSERT_NO_THROW_GMX(sel_[0].setEvaluateForces(true));
     ASSERT_NO_THROW_GMX(sel_[1].setEvaluateForces(true));
+    EXPECT_FALSE(sc_.requiredTopologyProperties().hasAny());
     ASSERT_NO_THROW_GMX(sc_.compile());
+    EXPECT_FALSE(sc_.requiredTopologyProperties().hasAny());
     EXPECT_TRUE(sel_[0].hasVelocities());
     EXPECT_TRUE(sel_[1].hasVelocities());
     EXPECT_TRUE(sel_[0].hasForces());
     EXPECT_TRUE(sel_[1].hasForces());
 }
 
+TEST_F(SelectionCollectionTest, HandlesForceRequestForCenterOfGeometry)
+{
+    ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromString("res_cog of atomnr 1 to 10"));
+    EXPECT_TRUE(sc_.requiredTopologyProperties().needsTopology);
+    ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
+    ASSERT_EQ(1U, sel_.size());
+    ASSERT_NO_THROW_GMX(sel_[0].setEvaluateForces(true));
+    // In principle, the code could know here that the masses are required, but
+    // currently it only knows this after compilation.
+    ASSERT_NO_THROW_GMX(sc_.compile());
+    EXPECT_TRUE(sc_.requiredTopologyProperties().needsMasses);
+    EXPECT_TRUE(sel_[0].hasForces());
+}
+
 TEST_F(SelectionCollectionTest, ParsesSelectionsFromFile)
 {
     ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromFile(
@@ -642,7 +671,7 @@ TEST_F(SelectionCollectionTest, HandlesFramesWithTooSmallAtomSubsets3)
 {
     const int index[] = { 0, 1, 2, 3, 4, 5, 6, 9, 10, 11 };
     // Evaluating the positions will require atoms 1-3, 7-12.
-    ASSERT_NO_THROW_GMX(sc_.parseFromString("whole_res_com of atomnr 2 7 11"));
+    ASSERT_NO_THROW_GMX(sc_.parseFromString("whole_res_cog of atomnr 2 7 11"));
     ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
     ASSERT_NO_THROW_GMX(sc_.compile());
     topManager_.initFrameIndices(index);
@@ -853,8 +882,9 @@ TEST_F(SelectionCollectionDataTest, HandlesMolIndex)
         "molecule 2 3 5"
     };
     ASSERT_NO_FATAL_FAILURE(runParser(selections));
-    ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
+    ASSERT_NO_FATAL_FAILURE(topManager_.loadTopology("simple.gro"));
     topManager_.initUniformMolecules(3);
+    ASSERT_NO_FATAL_FAILURE(setTopology());
     ASSERT_NO_FATAL_FAILURE(runCompiler());
 }
 
@@ -885,9 +915,10 @@ TEST_F(SelectionCollectionDataTest, HandlesAtomtype)
         "atomtype CA"
     };
     ASSERT_NO_FATAL_FAILURE(runParser(selections));
-    ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
+    ASSERT_NO_FATAL_FAILURE(topManager_.loadTopology("simple.gro"));
     const char *const types[] = { "CA", "SA", "SB" };
     topManager_.initAtomTypes(types);
+    ASSERT_NO_FATAL_FAILURE(setTopology());
     ASSERT_NO_FATAL_FAILURE(runCompiler());
 }
 
@@ -906,11 +937,15 @@ TEST_F(SelectionCollectionDataTest, HandlesMass)
         "mass > 5"
     };
     ASSERT_NO_FATAL_FAILURE(runParser(selections));
-    ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
-    for (int i = 0; i < top_->atoms.nr; ++i)
+    EXPECT_TRUE(sc_.requiredTopologyProperties().needsMasses);
+    ASSERT_NO_FATAL_FAILURE(topManager_.loadTopology("simple.gro"));
+    t_atoms &atoms = topManager_.atoms();
+    for (int i = 0; i < atoms.nr; ++i)
     {
-        top_->atoms.atom[i].m = 1.0 + i;
+        atoms.atom[i].m = 1.0 + i;
     }
+    atoms.haveMass = TRUE;
+    ASSERT_NO_FATAL_FAILURE(setTopology());
     ASSERT_NO_FATAL_FAILURE(runCompiler());
 }
 
@@ -920,13 +955,17 @@ TEST_F(SelectionCollectionDataTest, HandlesCharge)
         "charge < 0.5"
     };
     ASSERT_NO_FATAL_FAILURE(runParser(selections));
-    ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
-    for (int i = 0; i < top_->atoms.nr; ++i)
+    ASSERT_NO_FATAL_FAILURE(topManager_.loadTopology("simple.gro"));
+    t_atoms &atoms = topManager_.atoms();
+    for (int i = 0; i < atoms.nr; ++i)
     {
-        top_->atoms.atom[i].q = i / 10.0;
+        atoms.atom[i].q = i / 10.0;
     }
-    //ensure exact representation of 0.5 is used, so the test is always reproducible
-    top_->atoms.atom[5].q = 0.5;
+    // Ensure exact representation of 0.5 is used, so that the test is
+    // reproducible.
+    atoms.atom[5].q  = 0.5;
+    atoms.haveCharge = TRUE;
+    ASSERT_NO_FATAL_FAILURE(setTopology());
     ASSERT_NO_FATAL_FAILURE(runCompiler());
 }
 
@@ -1115,12 +1154,16 @@ TEST_F(SelectionCollectionDataTest, ComputesMassesAndCharges)
     setFlags(TestFlags() | efTestEvaluation | efTestPositionAtoms
              | efTestPositionMasses | efTestPositionCharges);
     ASSERT_NO_FATAL_FAILURE(runParser(selections));
-    ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
-    for (int i = 0; i < top_->atoms.nr; ++i)
+    ASSERT_NO_FATAL_FAILURE(topManager_.loadTopology("simple.gro"));
+    t_atoms &atoms = topManager_.atoms();
+    for (int i = 0; i < atoms.nr; ++i)
     {
-        top_->atoms.atom[i].m =   1.0 + i / 100.0;
-        top_->atoms.atom[i].q = -(1.0 + i / 100.0);
+        atoms.atom[i].m =   1.0 + i / 100.0;
+        atoms.atom[i].q = -(1.0 + i / 100.0);
     }
+    atoms.haveMass   = TRUE;
+    atoms.haveCharge = TRUE;
+    ASSERT_NO_FATAL_FAILURE(setTopology());
     ASSERT_NO_FATAL_FAILURE(runCompiler());
     ASSERT_NO_FATAL_FAILURE(runEvaluate());
     ASSERT_NO_FATAL_FAILURE(runEvaluateFinal());
@@ -1289,11 +1332,14 @@ TEST_F(SelectionCollectionDataTest, HandlesOverlappingRealRanges)
         "charge {0.05 to -0.3 -0.05 to 0.55}"
     };
     ASSERT_NO_FATAL_FAILURE(runParser(selections));
-    ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
-    for (int i = 0; i < top_->atoms.nr; ++i)
+    ASSERT_NO_FATAL_FAILURE(topManager_.loadTopology("simple.gro"));
+    t_atoms &atoms = topManager_.atoms();
+    for (int i = 0; i < atoms.nr; ++i)
     {
-        top_->atoms.atom[i].q = i / 10.0 - 0.5;
+        atoms.atom[i].q = i / 10.0 - 0.5;
     }
+    atoms.haveCharge = TRUE;
+    ASSERT_NO_FATAL_FAILURE(setTopology());
     ASSERT_NO_FATAL_FAILURE(runCompiler());
 }
 
index 8cd96fab1315ffa10d73d01ebe0fdb7cf82133fb..d6d6e7053fc6b5ba966b7f0daabdbc0907e34896 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -83,7 +83,7 @@ class SelectionOptionTestBase : public ::testing::Test
 };
 
 SelectionOptionTestBase::SelectionOptionTestBase()
-    : manager_(&sc_), options_(NULL, NULL)
+    : manager_(&sc_)
 {
     options_.addManager(&manager_);
     sc_.setReferencePosType("atom");
index 04796a2118fb9040ba2c66b139138dc11122fd58..4de0421cbc02f393b1a0a6c2ac622e1daf9b7e06 100644 (file)
@@ -51,6 +51,7 @@
 #include "gromacs/fileio/trxio.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/topology/atoms.h"
+#include "gromacs/topology/mtop_util.h"
 #include "gromacs/topology/topology.h"
 #include "gromacs/trajectory/trajectoryframe.h"
 #include "gromacs/utility/arrayref.h"
@@ -66,19 +67,19 @@ namespace test
 {
 
 TopologyManager::TopologyManager()
-    : top_(NULL), frame_(NULL)
+    : mtop_(nullptr), frame_(nullptr)
 {
 }
 
 TopologyManager::~TopologyManager()
 {
-    if (top_ != NULL)
+    if (mtop_ != nullptr)
     {
-        done_top(top_);
-        sfree(top_);
+        done_mtop(mtop_);
+        sfree(mtop_);
     }
 
-    if (frame_ != NULL)
+    if (frame_ != nullptr)
     {
         sfree(frame_->x);
         sfree(frame_->v);
@@ -86,11 +87,16 @@ TopologyManager::~TopologyManager()
         sfree(frame_->index);
         sfree(frame_);
     }
+
+    for (char *atomtype : atomtypes_)
+    {
+        sfree(atomtype);
+    }
 }
 
 void TopologyManager::requestFrame()
 {
-    GMX_RELEASE_ASSERT(top_ == NULL,
+    GMX_RELEASE_ASSERT(mtop_ == NULL,
                        "Frame must be requested before initializing topology");
     if (frame_ == NULL)
     {
@@ -122,19 +128,21 @@ void TopologyManager::requestForces()
 
 void TopologyManager::loadTopology(const char *filename)
 {
+    bool    fullTopology;
     int     ePBC;
     rvec   *xtop = NULL;
     matrix  box;
 
-    GMX_RELEASE_ASSERT(top_ == NULL, "Topology initialized more than once");
-    snew(top_, 1);
-    read_tps_conf(gmx::test::TestFileManager::getInputFilePath(filename).c_str(),
-                  top_, &ePBC, frame_ != NULL ? &xtop : NULL,
-                  NULL, box, FALSE);
+    GMX_RELEASE_ASSERT(mtop_ == nullptr, "Topology initialized more than once");
+    snew(mtop_, 1);
+    readConfAndTopology(
+            gmx::test::TestFileManager::getInputFilePath(filename).c_str(),
+            &fullTopology, mtop_, &ePBC, frame_ != NULL ? &xtop : NULL,
+            NULL, box);
 
     if (frame_ != NULL)
     {
-        frame_->natoms = top_->atoms.nr;
+        frame_->natoms = mtop_->natoms;
         frame_->bX     = TRUE;
         snew(frame_->x, frame_->natoms);
         std::memcpy(frame_->x, xtop, sizeof(*frame_->x) * frame_->natoms);
@@ -147,13 +155,26 @@ void TopologyManager::loadTopology(const char *filename)
 
 void TopologyManager::initAtoms(int count)
 {
-    GMX_RELEASE_ASSERT(top_ == NULL, "Topology initialized more than once");
-    snew(top_, 1);
-    init_t_atoms(&top_->atoms, count, FALSE);
+    GMX_RELEASE_ASSERT(mtop_ == NULL, "Topology initialized more than once");
+    snew(mtop_, 1);
+    mtop_->nmoltype = 1;
+    snew(mtop_->moltype, 1);
+    init_t_atoms(&mtop_->moltype[0].atoms, count, FALSE);
+    mtop_->nmolblock = 1;
+    snew(mtop_->molblock, 1);
+    mtop_->molblock[0].type            = 0;
+    mtop_->molblock[0].nmol            = 1;
+    mtop_->molblock[0].natoms_mol      = count;
+    mtop_->natoms                      = count;
+    mtop_->maxres_renum                = 0;
+    gmx_mtop_finalize(mtop_);
+    GMX_RELEASE_ASSERT(mtop_->maxres_renum == 0, "maxres_renum in mtop can be modified by an env.var., that is not supported in this test");
+    t_atoms &atoms = this->atoms();
     for (int i = 0; i < count; ++i)
     {
-        top_->atoms.atom[i].m = (i % 3 == 0 ? 2.0 : 1.0);
+        atoms.atom[i].m = (i % 3 == 0 ? 2.0 : 1.0);
     }
+    atoms.haveMass = TRUE;
     if (frame_ != NULL)
     {
         frame_->natoms = count;
@@ -172,52 +193,55 @@ void TopologyManager::initAtoms(int count)
 
 void TopologyManager::initAtomTypes(const ConstArrayRef<const char *> &types)
 {
-    GMX_RELEASE_ASSERT(top_ != NULL, "Topology not initialized");
+    GMX_RELEASE_ASSERT(mtop_ != nullptr, "Topology not initialized");
     atomtypes_.reserve(types.size());
     for (const char *type : types)
     {
         atomtypes_.push_back(gmx_strdup(type));
     }
-    snew(top_->atoms.atomtype, top_->atoms.nr);
-    size_t j = 0;
-    for (int i = 0; i < top_->atoms.nr; ++i, ++j)
+    t_atoms &atoms = this->atoms();
+    snew(atoms.atomtype, atoms.nr);
+    size_t   j = 0;
+    for (int i = 0; i < atoms.nr; ++i, ++j)
     {
         if (j == types.size())
         {
             j = 0;
         }
-        top_->atoms.atomtype[i] = &atomtypes_[j];
+        atoms.atomtype[i] = &atomtypes_[j];
     }
+    atoms.haveType = TRUE;
 }
 
 void TopologyManager::initUniformResidues(int residueSize)
 {
-    GMX_RELEASE_ASSERT(top_ != NULL, "Topology not initialized");
-    int residueIndex = -1;
-    for (int i = 0; i < top_->atoms.nr; ++i)
+    GMX_RELEASE_ASSERT(mtop_ != NULL, "Topology not initialized");
+    t_atoms &atoms        = this->atoms();
+    int      residueIndex = -1;
+    for (int i = 0; i < atoms.nr; ++i)
     {
         if (i % residueSize == 0)
         {
             ++residueIndex;
         }
-        top_->atoms.atom[i].resind = residueIndex;
+        atoms.atom[i].resind = residueIndex;
     }
 }
 
 void TopologyManager::initUniformMolecules(int moleculeSize)
 {
-    GMX_RELEASE_ASSERT(top_ != NULL, "Topology not initialized");
+    GMX_RELEASE_ASSERT(mtop_ != NULL, "Topology not initialized");
     int index = 0;
-    top_->mols.nalloc_index = (top_->atoms.nr + moleculeSize - 1) / moleculeSize + 1;
-    snew(top_->mols.index, top_->mols.nalloc_index);
-    top_->mols.nr = 0;
-    while (index < top_->atoms.nr)
+    mtop_->mols.nalloc_index = (mtop_->natoms + moleculeSize - 1) / moleculeSize + 1;
+    srenew(mtop_->mols.index, mtop_->mols.nalloc_index);
+    mtop_->mols.nr = 0;
+    while (index < mtop_->natoms)
     {
-        top_->mols.index[top_->mols.nr] = index;
-        ++top_->mols.nr;
+        mtop_->mols.index[mtop_->mols.nr] = index;
+        ++mtop_->mols.nr;
         index += moleculeSize;
     }
-    top_->mols.index[top_->mols.nr] = top_->atoms.nr;
+    mtop_->mols.index[mtop_->mols.nr] = mtop_->natoms;
 }
 
 void TopologyManager::initFrameIndices(const ConstArrayRef<int> &index)
@@ -232,5 +256,13 @@ void TopologyManager::initFrameIndices(const ConstArrayRef<int> &index)
     frame_->natoms = index.size();
 }
 
+t_atoms &TopologyManager::atoms()
+{
+    GMX_RELEASE_ASSERT(mtop_ != nullptr, "Topology not initialized");
+    GMX_RELEASE_ASSERT(mtop_->natoms == mtop_->moltype[0].atoms.nr,
+                       "Test setup assumes all atoms in a single molecule type");
+    return mtop_->moltype[0].atoms;
+}
+
 } // namespace test
 } // namespace gmx
index 9adc4a30575406df33d4d3f8f91bf7217a3340ce..4b5b9dd3bcaf872da8a2e087c58694c8c16ef68a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -44,7 +44,8 @@
 
 #include <vector>
 
-struct t_topology;
+struct gmx_mtop_t;
+struct t_atoms;
 struct t_trxframe;
 
 namespace gmx
@@ -74,11 +75,12 @@ class TopologyManager
 
         void initFrameIndices(const ConstArrayRef<int> &index);
 
-        t_topology *topology() { return top_; }
+        gmx_mtop_t *topology() { return mtop_; }
+        t_atoms &atoms();
         t_trxframe *frame() { return frame_; }
 
     private:
-        t_topology             *top_;
+        gmx_mtop_t             *mtop_;
         t_trxframe             *frame_;
         std::vector<char *>     atomtypes_;
 };
index ab9e2290756eb6abbe1cfda5013688f8bc973a51..d2c318a923585f0fd79246e3c86a5395f57cabf9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -42,9 +42,7 @@ namespace gmx
 static inline void
 simdPrefetch(const void * m)
 {
-#if defined(__ibmxl__) || defined(__xlC__)
-    __dcbt(m);
-#elif defined __GNUC__
+#if defined __GNUC__
     __builtin_prefetch(m);
 #endif
 }
index e0dd99d00a1ef6892370c58f25ee7ad66f06adc6..c93403685207532e12a47eeb0be02ae9696090ab 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -41,6 +41,7 @@
 #include "config.h"
 
 // Assert is buggy on xlc with high optimization, so we skip it for QPX
+// TODO Add back the asserts for bgclang
 #include <cstddef>
 
 #ifdef __clang__
index bf81c8b3b356189dda06b96c37f8729835102ecb..f2b5a20d926d932e34e34071acc9c493f11fdbc2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -36,8 +36,6 @@
 #ifndef GMX_SIMD_IMPL_X86_AVX_128_FMA_DEFINITIONS_H
 #define GMX_SIMD_IMPL_X86_AVX_128_FMA_DEFINITIONS_H
 
-#include "config.h"
-
 // Capability definitions for AVX-128-FMA
 #define GMX_SIMD                                1
 #define GMX_SIMD_HAVE_FLOAT                     1
 #define GMX_SIMD_RSQRT_BITS                    11
 #define GMX_SIMD_RCP_BITS                      11
 
-// Work around gcc bug with wrong type for mask formal parameter to maskload/maskstore
-#if GMX_SIMD_X86_AVX_GCC_MASKLOAD_BUG
-#    define gmx_mm_maskload_ps(mem, mask)       _mm_maskload_ps((mem), _mm_castsi128_ps(mask))
-#    define gmx_mm_maskstore_ps(mem, mask, x)   _mm_maskstore_ps((mem), _mm_castsi128_ps(mask), (x))
-#else
-#    define gmx_mm_maskload_ps(mem, mask)       _mm_maskload_ps((mem), (mask))
-#    define gmx_mm_maskstore_ps(mem, mask, x)   _mm_maskstore_ps((mem), (mask), (x))
-#endif
+#define gmx_mm_maskload_ps(mem, mask)       _mm_maskload_ps((mem), (mask))
+#define gmx_mm_maskstore_ps(mem, mask, x)   _mm_maskstore_ps((mem), (mask), (x))
 
 #endif  // GMX_SIMD_IMPL_X86_AVX_128_FMA_DEFINITIONS_H
index 1746edfa87dea0e9f05a256bdaab55ebf70f8ac1..e1a035e957759d921da03316e027ff5e2a4fd74a 100644 (file)
@@ -62,7 +62,7 @@
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/timing/wallcycle.h"
-#include "gromacs/topology/mtop_util.h"
+#include "gromacs/topology/mtop_lookup.h"
 #include "gromacs/topology/topology.h"
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/fatalerror.h"
@@ -975,17 +975,16 @@ static int get_group_apm_check(
         int                         igroup,
         t_swap                     *s,
         gmx_bool                    bVerbose,
-        const gmx_mtop_atomlookup_t alook,
         gmx_mtop_t                 *mtop)
 {
-    int        molb, molnr, atnr_mol;
     t_swapgrp *g   = &s->group[igroup];
     int       *ind = s->group[igroup].ind;
     int        nat = s->group[igroup].nat;
 
     /* Determine the number of solvent atoms per solvent molecule from the
      * first solvent atom: */
-    gmx_mtop_atomnr_to_molblock_ind(alook, ind[0], &molb, &molnr, &atnr_mol);
+    int molb = 0;
+    mtopGetMolblockIndex(mtop, ind[0], &molb, NULL, NULL);
     int apm = mtop->molblock[molb].natoms_mol;
 
     if (bVerbose)
@@ -997,7 +996,7 @@ static int get_group_apm_check(
     /* Check whether this is also true for all other solvent atoms */
     for (int i = 1; i < nat; i++)
     {
-        gmx_mtop_atomnr_to_molblock_ind(alook, ind[i], &molb, &molnr, &atnr_mol);
+        mtopGetMolblockIndex(mtop, ind[i], &molb, NULL, NULL);
         if (apm != mtop->molblock[molb].natoms_mol)
         {
             gmx_fatal(FARGS, "Not all molecules of swap group %d consist of %d atoms.",
@@ -1388,8 +1387,6 @@ void convertOldToNewGroupFormat(
         gmx_bool      bVerbose,
         t_commrec    *cr)
 {
-    t_atom                *atom;
-    gmx_mtop_atomlookup_t  alook = gmx_mtop_atomlookup_init(mtop);
     t_swapGroup           *g     = &sc->grp[3];
 
     /* Loop through the atom indices of group #3 (anions) and put all indices
@@ -1402,10 +1399,11 @@ void convertOldToNewGroupFormat(
     snew(indAnions, g->nat);
     snew(indCations, g->nat);
 
+    int molb = 0;
     for (int i = 0; i < g->nat; i++)
     {
-        gmx_mtop_atomnr_to_atom(alook, g->ind[i], &atom);
-        if (atom->q < 0)
+        const t_atom &atom = mtopGetAtomParameters(mtop, g->ind[i], &molb);
+        if (atom.q < 0)
         {
             // This is an anion, add it to the list of anions
             indAnions[nAnions++] = g->ind[i];
@@ -1459,23 +1457,19 @@ void init_swapcoords(
         gmx_mtop_t             *mtop,
         rvec                    x[],
         matrix                  box,
-        swapstate_t            *swapstate,
+        swapstate_t           **swapstatePtr,
         t_commrec              *cr,
         const gmx_output_env_t *oenv,
         unsigned long           Flags)
 {
     t_swapcoords          *sc;
     t_swap                *s;
-    t_atom                *atom;
     t_swapgrp             *g;
     swapstateIons_t       *gs;
     gmx_bool               bAppend, bStartFromCpt, bRerun;
-    gmx_mtop_atomlookup_t  alook = NULL;
     matrix                 boxCopy;
 
 
-    alook = gmx_mtop_atomlookup_init(mtop);
-
     if ( (PAR(cr)) && !DOMAINDECOMP(cr) )
     {
         gmx_fatal(FARGS, "Position swapping is only implemented for domain decomposition!");
@@ -1562,6 +1556,12 @@ void init_swapcoords(
         }
     }
 
+    if (*swapstatePtr == NULL)
+    {
+        snew(*swapstatePtr, 1);
+    }
+    swapstate_t *swapstate = *swapstatePtr;
+
     if (MASTER(cr))
     {
         init_swapstate(swapstate, sc, mtop, x, box, ir->ePBC);
@@ -1585,17 +1585,18 @@ void init_swapcoords(
         real charge;
 
         g      = &(s->group[ig]);
-        g->apm = get_group_apm_check(ig, s, MASTER(cr) && bVerbose, alook, mtop);
+        g->apm = get_group_apm_check(ig, s, MASTER(cr) && bVerbose, mtop);
 
         /* Since all molecules of a group are equal, we only need enough space
          * to determine properties of a single molecule at at time */
         snew(g->m, g->apm);  /* For the center of mass */
         charge = 0;          /* To determine the charge imbalance */
+        int molb = 0;
         for (int j = 0; j < g->apm; j++)
         {
-            gmx_mtop_atomnr_to_atom(alook, g->ind[j], &atom);
-            g->m[j] = atom->m;
-            charge += atom->q;
+            const t_atom &atom = mtopGetAtomParameters(mtop, g->ind[j], &molb);
+            g->m[j] = atom.m;
+            charge += atom.q;
         }
         /* Total charge of one molecule of this group: */
         g->q = charge;
@@ -1610,10 +1611,10 @@ void init_swapcoords(
         {
             /* Save the split group masses if mass-weighting is requested */
             snew(g->m, g->nat);
+            int molb = 0;
             for (int i = 0; i < g->nat; i++)
             {
-                gmx_mtop_atomnr_to_atom(alook, g->ind[i], &atom);
-                g->m[i] = atom->m;
+                g->m[i] = mtopGetAtomMass(mtop, g->ind[i], &molb);
             }
         }
     }
@@ -1991,7 +1992,6 @@ gmx_bool do_swapcoords(
         gmx_wallcycle_t   wcycle,
         rvec              x[],
         matrix            box,
-        gmx_mtop_t       *mtop,
         gmx_bool          bVerbose,
         gmx_bool          bRerun)
 {
@@ -2003,7 +2003,6 @@ gmx_bool do_swapcoords(
     t_swapgrp            *g, *gsol;
     int                   isol, iion;
     rvec                  com_solvent, com_particle; /* solvent and swap molecule's center of mass */
-    gmx_mtop_atomlookup_t alook = NULL;
 
 
     wallcycle_start(wcycle, ewcSWAP);
@@ -2083,7 +2082,6 @@ gmx_bool do_swapcoords(
         }
 
         /* Now actually perform the particle exchanges, one swap group after another */
-        alook  = gmx_mtop_atomlookup_init(mtop);
         gsol   = &s->group[eGrpSolvent];
         for (ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
         {
@@ -2145,7 +2143,6 @@ gmx_bool do_swapcoords(
                         SwS, nswaps, nswaps > 1 ? "s" : "", step, g->molname);
             }
         }
-        gmx_mtop_atomlookup_destroy(alook);
 
         if (s->fpout != NULL)
         {
index 8ce0b590f7cbb48d49cb75edcf56c817e567f4f4..9f7d556155d0d735c7352a42fae537ef5547e5e1 100644 (file)
@@ -74,7 +74,7 @@ struct t_swapcoords;
  * \param[in] mtop          Molecular topology.
  * \param[in] x             The initial positions of all particles.
  * \param[in] box           The simulation box.
- * \param[in] swapstate     Swap-related data that is read from or written to checkpoint.
+ * \param[in] swapstatePtr  Swap-related data that is read from or written to checkpoint.
  * \param[in] cr            Pointer to MPI communication data.
  * \param[in] oenv          Needed to open the swap output XVGR file.
  * \param[in] Flags         Flags passed over from main, used to determine
@@ -88,7 +88,7 @@ void init_swapcoords(
         gmx_mtop_t             *mtop,
         rvec                    x[],
         matrix                  box,
-        swapstate_t            *swapstate,
+        swapstate_t           **swapstatePtr,
         t_commrec              *cr,
         const gmx_output_env_t *oenv,
         unsigned long           Flags);
@@ -121,7 +121,6 @@ void dd_make_local_swap_groups(gmx_domdec_t *dd, t_swapcoords *si_pub);
  * \param[in] wcycle   Count wallcycles of swap routines for diagnostic output.
  * \param[in] x        Positions of home particles this node owns.
  * \param[in] box      The simulation box.
- * \param[in] mtop     Molecular topology.
  * \param[in] bVerbose Should we be quiet or verbose?
  * \param[in] bRerun   Are we doing a rerun?
  *
@@ -135,7 +134,6 @@ gmx_bool do_swapcoords(
         gmx_wallcycle_t   wcycle,
         rvec              x[],
         matrix            box,
-        gmx_mtop_t       *mtop,
         gmx_bool          bVerbose,
         gmx_bool          bRerun);
 
index 6b4ed587fe4d0ee69ff2c60f7b9912eb8317e001..935f31a0fc268117063fce3563c00b889753a826 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2015, by the GROMACS development team, led by
+# Copyright (c) 2015,2016, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -36,5 +36,5 @@ file(GLOB TABLE_SOURCES *.cpp)
 set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${TABLE_SOURCES} PARENT_SCOPE)
 
 if (BUILD_TESTING)
-#    add_subdirectory(tests)
+    add_subdirectory(tests)
 endif()
diff --git a/src/gromacs/tables/cubicsplinetable.cpp b/src/gromacs/tables/cubicsplinetable.cpp
new file mode 100644 (file)
index 0000000..f0b589e
--- /dev/null
@@ -0,0 +1,490 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+
+/*! \internal \file
+ * \brief
+ * Implements classes for cubic spline table functions
+ *
+ * \author Erik Lindahl <erik.lindahl@gmail.com>
+ * \ingroup module_tables
+ */
+#include "gmxpre.h"
+
+#include "cubicsplinetable.h"
+
+#include <cmath>
+
+#include <algorithm>
+#include <functional>
+#include <initializer_list>
+#include <utility>
+#include <vector>
+
+#include "gromacs/tables/tableinput.h"
+#include "gromacs/utility/alignedallocator.h"
+#include "gromacs/utility/arrayref.h"
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/real.h"
+
+#include "splineutil.h"
+
+namespace gmx
+{
+
+namespace
+{
+
+/*! \brief Calculate table elements from function/derivative data
+ *
+ * \param functionValue0   Function value for the present table index
+ * \param functionValue1   Function value for the next table index
+ * \param derivativeValue0 Derivative value for the present table index
+ * \param derivativeValue1 Derivative value for the next table index
+ * \param spacing          Distance between table points
+ * \param Y                Function value for table index
+ * \param F                Component to multiply with offset eps
+ * \param G                Component to multiply with eps^2
+ * \param H                Component to multiply with eps^3
+ */
+void
+calculateCubicSplineCoefficients(double  functionValue0,
+                                 double  functionValue1,
+                                 double  derivativeValue0,
+                                 double  derivativeValue1,
+                                 double  spacing,
+                                 double *Y,
+                                 double *F,
+                                 double *G,
+                                 double *H)
+{
+    *Y  =  functionValue0;
+    *F  =  spacing * derivativeValue0;
+    *G  =  3.0*( functionValue1 - functionValue0) - spacing * (derivativeValue1 + 2.0 * derivativeValue0);
+    *H  = -2.0*( functionValue1 - functionValue0) + spacing * (derivativeValue1 + derivativeValue0);
+}
+
+/*! \brief Perform cubic spline interpolation in interval from function/derivative
+ *
+ * \param      functionValue0               Function value for the present table index
+ * \param      functionValue1               Function value for the next table index
+ * \param      derivativeValue0             Derivative value for the present table index
+ * \param      derivativeValue1             Derivative value for the next table index
+ * \param      spacing                      Distance between table points
+ * \param      eps                          Offset from lower table point for evaluation
+ * \param[out] interpolatedFunctionValue    Output function value
+ * \param[out] interpolatedDerivativeValue  Output derivative value
+ */
+void
+cubicSplineInterpolationFromFunctionAndDerivative(double  functionValue0,
+                                                  double  functionValue1,
+                                                  double  derivativeValue0,
+                                                  double  derivativeValue1,
+                                                  double  spacing,
+                                                  double  eps,
+                                                  double *interpolatedFunctionValue,
+                                                  double *interpolatedDerivativeValue)
+{
+    double Y, F, G, H;
+
+    calculateCubicSplineCoefficients(functionValue0, functionValue1,
+                                     derivativeValue0, derivativeValue1,
+                                     spacing,
+                                     &Y, &F, &G, &H);
+
+    double Fp = fma(fma(H, eps, G), eps, F);
+
+    *interpolatedFunctionValue   = fma(Fp, eps, Y);
+    *interpolatedDerivativeValue = fma(eps, fma(2.0*eps, H, G), Fp)/spacing;
+}
+
+
+
+/*! \brief Construct the data for a single cubic table from analytical functions
+ *
+ * \param[in]  function             Analytical functiojn
+ * \param[in]  derivative           Analytical derivative
+ * \param[in]  range                Upper/lower limit of region to tabulate
+ * \param[in]  spacing              Distance between table points
+ * \param[out] yfghTableData        Output cubic spline table with Y,F,G,H entries
+ */
+void
+fillSingleCubicSplineTableData(const std::function<double(double)>   &function,
+                               const std::function<double(double)>   &derivative,
+                               const std::pair<real, real>           &range,
+                               double                                 spacing,
+                               std::vector<real>                     *yfghTableData)
+{
+    int  endIndex   = range.second / spacing + 2;
+
+    yfghTableData->resize(4*endIndex);
+
+    double       maxMagnitude      = 0.0001*GMX_REAL_MAX;
+    bool         functionIsInRange = true;
+    std::size_t  lastIndexInRange  = endIndex - 1;
+
+    for (int i = endIndex - 1; i >= 0; i--)
+    {
+        double x                    = i * spacing;
+        double tmpFunctionValue;
+        double tmpDerivativeValue;
+        double nextHigherFunction;
+        double nextHigherDerivative;
+        double Y, F, G, H;
+
+        if (range.first > 0 && i == 0)
+        {
+            // Avoid x==0 if it is not in the range, since it can lead to
+            // singularities even if the value for i==1 was within or required magnitude
+            functionIsInRange = false;
+        }
+
+        if (functionIsInRange)
+        {
+            tmpFunctionValue     = function(x);
+            tmpDerivativeValue   = derivative(x);
+            nextHigherFunction   = ((i+1) < endIndex) ? function(x+spacing) : 0.0;
+            nextHigherDerivative = ((i+1) < endIndex) ? derivative(x+spacing) : 0.0;
+
+            if (std::abs(tmpFunctionValue) > maxMagnitude || std::abs(tmpDerivativeValue) > maxMagnitude)
+            {
+                functionIsInRange = false; // Once this happens, it never resets to true again
+            }
+        }
+
+        if (functionIsInRange)
+        {
+            calculateCubicSplineCoefficients(tmpFunctionValue, nextHigherFunction,
+                                             tmpDerivativeValue, nextHigherDerivative,
+                                             spacing,
+                                             &Y, &F, &G, &H);
+            lastIndexInRange--;
+        }
+        else
+        {
+            double lastIndexY = (*yfghTableData)[4*lastIndexInRange];
+            double lastIndexF = (*yfghTableData)[4*lastIndexInRange + 1];
+
+            Y = lastIndexY + lastIndexF * (i - lastIndexInRange);
+            F = lastIndexF;
+            G = 0.0;
+            H = 0.0;
+        }
+
+        (*yfghTableData)[4*i  ] = Y;
+        (*yfghTableData)[4*i+1] = F;
+        (*yfghTableData)[4*i+2] = G;
+        (*yfghTableData)[4*i+3] = H;
+    }
+}
+
+
+/*! \brief Construct the data for a single cubic table from vector data
+ *
+ * \param[in]  function             Input vector with function data
+ * \param[in]  derivative           Input vector with derivative data
+ * \param[in]  inputSpacing         Distance between points in input vectors
+ * \param[in]  range                Upper/lower limit of region to tabulate
+ * \param[in]  spacing              Distance between table points
+ * \param[out] yfghTableData        Output cubic spline table with Y,F,G,H entries
+ */
+void
+fillSingleCubicSplineTableData(ConstArrayRef<double>                  function,
+                               ConstArrayRef<double>                  derivative,
+                               double                                 inputSpacing,
+                               const std::pair<real, real>           &range,
+                               double                                 spacing,
+                               std::vector<real>                     *yfghTableData)
+{
+    int                 endIndex   = range.second / spacing + 2;
+
+    std::vector<double> tmpFunction(endIndex);
+    std::vector<double> tmpDerivative(endIndex);
+
+    double              maxMagnitude      = 0.0001*GMX_REAL_MAX;
+    bool                functionIsInRange = true;
+    std::size_t         lastIndexInRange  = endIndex - 1;
+
+    // Interpolate function and derivative values in positions needed for output
+    for (int i = endIndex - 1; i >= 0; i--)
+    {
+        double x     = i * spacing;
+        double xtab  = x / inputSpacing;
+        int    index = xtab;
+        double eps   = xtab - index;
+
+        if (range.first > 0 && i == 0)
+        {
+            // Avoid x==0 if it is not in the range, since it can lead to
+            // singularities even if the value for i==1 was within or required magnitude
+            functionIsInRange = false;
+        }
+
+        if (functionIsInRange && (std::abs(function[index]) > maxMagnitude || std::abs(derivative[index]) > maxMagnitude))
+        {
+            functionIsInRange = false; // Once this happens, it never resets to true again
+        }
+
+        if (functionIsInRange)
+        {
+            cubicSplineInterpolationFromFunctionAndDerivative(function[index],
+                                                              function[index+1],
+                                                              derivative[index],
+                                                              derivative[index+1],
+                                                              inputSpacing,
+                                                              eps,
+                                                              &(tmpFunction[i]),
+                                                              &(tmpDerivative[i]));
+            lastIndexInRange--;
+        }
+        else
+        {
+            double lastIndexFunction   = tmpFunction[lastIndexInRange];
+            double lastIndexDerivative = tmpDerivative[lastIndexInRange];
+            tmpFunction[i]             = lastIndexFunction + lastIndexDerivative * (i - lastIndexInRange) * spacing;
+            tmpDerivative[i]           = lastIndexDerivative;
+        }
+    }
+
+    yfghTableData->resize(4*endIndex);
+
+    for (int i = 0; i < endIndex; i++)
+    {
+        double Y, F, G, H;
+
+        double nextFunction   = ((i+1) < endIndex) ? tmpFunction[i+1] : 0.0;
+        double nextDerivative = ((i+1) < endIndex) ? tmpDerivative[i+1] : 0.0;
+
+        calculateCubicSplineCoefficients(tmpFunction[i], nextFunction,
+                                         tmpDerivative[i], nextDerivative,
+                                         spacing,
+                                         &Y, &F, &G, &H);
+        (*yfghTableData)[4*i  ] = Y;
+        (*yfghTableData)[4*i+1] = F;
+        (*yfghTableData)[4*i+2] = G;
+        (*yfghTableData)[4*i+3] = H;
+    }
+
+}
+
+}   // namespace anonymous
+
+
+
+#if GMX_DOUBLE
+const real
+CubicSplineTable::defaultTolerance = 1e-10;
+#else
+const real
+CubicSplineTable::defaultTolerance = 10.0 * GMX_FLOAT_EPS;
+#endif
+
+CubicSplineTable::CubicSplineTable(std::initializer_list<AnalyticalSplineTableInput>   analyticalInputList,
+                                   const std::pair<real, real>                        &range,
+                                   real                                                tolerance)
+    : numFuncInTable_(analyticalInputList.size()), range_(range)
+{
+    // Sanity check on input values
+    if (range_.first < 0.0 || (range_.second-range_.first) < 0.001)
+    {
+        GMX_THROW(InvalidInputError("Range to tabulate cannot include negative values and must span at least 0.001"));
+    }
+
+    if (tolerance < GMX_REAL_EPS)
+    {
+        GMX_THROW(ToleranceError("Table tolerance cannot be smaller than GMX_REAL_EPS"));
+    }
+
+    double minQuotient = GMX_REAL_MAX;
+
+    // loop over all functions to find smallest spacing
+    for (auto thisFuncInput : analyticalInputList)
+    {
+        try
+        {
+            internal::throwUnlessDerivativeIsConsistentWithFunction(thisFuncInput.function, thisFuncInput.derivative, range_);
+        }
+        catch (gmx::GromacsException &ex)
+        {
+            ex.prependContext("Error generating cubic spline table for function '" + thisFuncInput.desc + "'");
+            throw;
+        }
+        // Calculate the required table spacing h. The error we make with linear interpolation
+        // of the derivative will be described by the third-derivative correction term.
+        // This means we can compute the required spacing as h = sqrt(12*tolerance*min(f'/f''')),
+        // where f'/f''' is the first and third derivative of the function, respectively.
+
+        double thisMinQuotient = internal::findSmallestQuotientOfFunctionAndThirdDerivative(thisFuncInput.derivative, range_);
+
+        minQuotient = std::min(minQuotient, thisMinQuotient);
+    }
+
+    double spacing = 0.5 * std::cbrt(72.0 * std::sqrt(3.0) * tolerance * minQuotient);
+
+    tableScale_  = 1.0 / spacing;
+
+    if (range_.second * tableScale_ > 2e6)
+    {
+        GMX_THROW(ToleranceError("Over a million points would be required for table; decrease range or increase tolerance"));
+    }
+
+    // Loop over all tables again.
+    // Here we create the actual table for each function, and then
+    // combine them into a multiplexed table function.
+    std::size_t funcIndex = 0;
+
+    for (auto thisFuncInput : analyticalInputList)
+    {
+        try
+        {
+            std::vector<real> tmpYfghTableData;
+
+            fillSingleCubicSplineTableData(thisFuncInput.function,
+                                           thisFuncInput.derivative,
+                                           range_,
+                                           spacing,
+                                           &tmpYfghTableData);
+
+            internal::fillMultiplexedTableData(tmpYfghTableData, &yfghMultiTableData_,
+                                               4, numFuncInTable_, funcIndex);
+
+            funcIndex++;
+        }
+        catch (gmx::GromacsException &ex)
+        {
+            ex.prependContext("Error generating cubic spline table for function '" + thisFuncInput.desc + "'");
+            throw;
+        }
+    }
+}
+
+
+CubicSplineTable::CubicSplineTable(std::initializer_list<NumericalSplineTableInput>   numericalInputList,
+                                   const std::pair<real, real>                       &range,
+                                   real                                               tolerance)
+    : numFuncInTable_(numericalInputList.size()), range_(range)
+{
+    // Sanity check on input values
+    if (range.first < 0.0 || (range.second-range.first) < 0.001)
+    {
+        GMX_THROW(InvalidInputError("Range to tabulate cannot include negative values and must span at least 0.001"));
+    }
+
+    if (tolerance < GMX_REAL_EPS)
+    {
+        GMX_THROW(ToleranceError("Table tolerance cannot be smaller than GMX_REAL_EPS"));
+    }
+
+    double minQuotient = GMX_REAL_MAX;
+
+    // loop over all functions to find smallest spacing
+    for (auto thisFuncInput : numericalInputList)
+    {
+        try
+        {
+            // We do not yet know what the margin is, but we need to test that we at least cover
+            // the requested range before starting to calculate derivatives
+            if (thisFuncInput.function.size() < range_.second / thisFuncInput.spacing + 1)
+            {
+                GMX_THROW(InconsistentInputError("Table input vectors must cover requested range, and a margin beyond the upper endpoint"));
+            }
+
+            if (thisFuncInput.function.size() != thisFuncInput.derivative.size())
+            {
+                GMX_THROW(InconsistentInputError("Function and derivative vectors have different lengths"));
+            }
+
+            internal::throwUnlessDerivativeIsConsistentWithFunction(thisFuncInput.function, thisFuncInput.derivative, thisFuncInput.spacing, range_);
+        }
+        catch (gmx::GromacsException &ex)
+        {
+            ex.prependContext("Error generating cubic spline table for function '" + thisFuncInput.desc + "'");
+            throw;
+        }
+        // Calculate the required table spacing h. The error we make with linear interpolation
+        // of the derivative will be described by the third-derivative correction term.
+        // This means we can compute the required spacing as h = sqrt(12*tolerance*min(f'/f''')),
+        // where f'/f''' is the first and third derivative of the function, respectively.
+
+        double thisMinQuotient = internal::findSmallestQuotientOfFunctionAndThirdDerivative(thisFuncInput.derivative, thisFuncInput.spacing, range_);
+
+        minQuotient = std::min(minQuotient, thisMinQuotient);
+    }
+
+    double spacing     = std::cbrt(72.0 * std::sqrt(3.0) * tolerance * minQuotient);
+
+    tableScale_  = 1.0 / spacing;
+
+    if (range_.second * tableScale_ > 1e6)
+    {
+        GMX_THROW(ToleranceError("Requested tolerance would require over a million points in table"));
+    }
+
+    // Loop over all tables again.
+    // Here we create the actual table for each function, and then
+    // combine them into a multiplexed table function.
+    std::size_t funcIndex = 0;
+
+    for (auto thisFuncInput : numericalInputList)
+    {
+        try
+        {
+            if (spacing < thisFuncInput.spacing)
+            {
+                GMX_THROW(ToleranceError("Input vector spacing cannot achieve tolerance requested"));
+            }
+
+            std::vector<real> tmpYfghTableData;
+
+            fillSingleCubicSplineTableData(thisFuncInput.function,
+                                           thisFuncInput.derivative,
+                                           thisFuncInput.spacing,
+                                           range,
+                                           spacing,
+                                           &tmpYfghTableData);
+
+            internal::fillMultiplexedTableData(tmpYfghTableData, &yfghMultiTableData_,
+                                               4, numFuncInTable_, funcIndex);
+
+            funcIndex++;
+        }
+        catch (gmx::GromacsException &ex)
+        {
+            ex.prependContext("Error generating cubic spline table for function '" + thisFuncInput.desc + "'");
+            throw;
+        }
+    }
+}
+
+} // namespace gmx
diff --git a/src/gromacs/tables/cubicsplinetable.h b/src/gromacs/tables/cubicsplinetable.h
new file mode 100644 (file)
index 0000000..c112211
--- /dev/null
@@ -0,0 +1,645 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+
+/*! \libinternal \file
+ * \brief
+ * Declares classes for cubic spline table
+ *
+ * \inlibraryapi
+ * \author Erik Lindahl <erik.lindahl@gmail.com>
+ * \ingroup module_tables
+ */
+#ifndef GMX_TABLES_CUBICSPLINETABLE_H
+#define GMX_TABLES_CUBICSPLINETABLE_H
+
+#include <initializer_list>
+#include <vector>
+
+#include "gromacs/simd/simd.h"
+#include "gromacs/tables/tableinput.h"
+#include "gromacs/utility/alignedallocator.h"
+#include "gromacs/utility/classhelpers.h"
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/real.h"
+
+namespace gmx
+{
+
+/*! \libinternal \brief Cubic spline interpolation table.
+ *
+ * This class interpolates a function specified either as an analytical
+ * expression or from user-provided table data.
+ *
+ * At initialization, you provide the reference function of vectors
+ * as a list of tuples that contain a brief name, the function, and
+ * derivative for each function to tabulate. To create a table with
+ * two functions this initializer list can for instance look like
+ *
+ *     { {"LJ6", lj6Func, lj6Der}, {"LJ12", lj12Func, lj12Der} }
+ *
+ * The names are only used so exceptions during initialization can
+ * be traced to a specific table.
+ *
+ * When interpolating, there are methods to interpolate either 1, 2, or 3
+ * functions in one go. By default these interpolation routines will
+ * operate on tables with the same number of functions as specified in
+ * the interpolation method (debug builds check that this is consistent with
+ * the table). However, it is also possible to use optional template
+ * parameters that specify the total number of functions in a table, and
+ * what function index to interpolate. For instance, to interpolate the
+ * derivative of the second function (i.e., index 1) in a
+ * multi-function-table with three functions in total, you can write
+ *
+ *     table.evaluateDerivative<3,1>(x,&der);
+ *
+ * Here too, debug builds will check that the template parameters are
+ * consistent with the table.
+ *
+ * This class interpolates a function specified either as an analytical
+ * expression or from user-provided table data. The coefficients for each
+ * table point are precalculated such that we simply evaluate
+ *
+ * \f{eqnarray*}{
+ * V(x)  = Y + F \epsilon + G \epsilon^2 + H \epsilon^3
+ * V'(x) = (F + 2 G \epsilon + 3 H \epsilon^2)/h
+ * \f}
+ *
+ * Where h is the spacing and epsilon the fractional offset from table point.
+ *
+ * While it is possible to create tables only from function values
+ * (i.e., no derivatives), it is recommended to provide derivatives for higher
+ * accuracy and to avoid issues with numerical differentiation. Note that the
+ * table input should be smooth, i.e. it should not contain noise e.g. from an
+ * (iterative) Boltzmann inversion procedure - you have been warned.
+ *
+ * \note This class is responsible for fundamental interpolation of any function,
+ *       which might or might not correspond to a potential. For this reason
+ *       both input and output derivatives are proper function derivatives, and
+ *       we do not swap any signs to get forces directly from the table.
+ *
+ * \note There will be a small additional accuracy loss from the internal
+ *       operation where we calculate the epsilon offset from the nearest table
+ *       point, since the integer part we subtract can get large in those cases.
+ *
+ *       While this is technically possible to solve with extended precision
+ *       arithmetics, that would introduce extra instructions in some highly
+ *       performance-sensitive code parts. For typical GROMACS interaction
+ *       functions the derivatives will decay faster than the potential, which
+ *       means it will never play any role. For other functions it will only
+ *       cause a small increase in the relative error for arguments where the
+ *       magnitude of the function or derivative is very small.
+ *       Since we typically sum several results in GROMACS, this should never
+ *       show up in any real cases, and for this reason we choose not to do
+ *       the extended precision arithmetics.
+ *
+ * \note These routines are not suitable for table ranges starting far away
+ *       from zero, since we allocate memory and calculate indices starting from
+ *       range zero for efficiency reasons.
+ */
+class CubicSplineTable
+{
+    private:
+        /*! \brief Change that function value falls inside range when debugging
+         *
+         *  \tparam T   Lookup argument floating-point type, typically SimdReal or real.
+         *  \param  r   Lookup argument to test
+         *
+         *  \throws Debug builds will throw gmx::RangeError for values that are
+         *          larger than the upper limit of the range, or smaller than 0.
+         *          We allow the table to be called with arguments between 0 and
+         *          the lower limit of the range, since this might in theory occur
+         *          once-in-a-blue-moon with some algorithms.
+         */
+        template <typename T>
+        void
+        rangeCheck(T gmx_unused r) const
+        {
+#ifndef NDEBUG
+            // Check that all values fall in range when debugging
+            if (anyTrue( r < T(0.0) || T(range_.second) <= r ) )
+            {
+                GMX_THROW(RangeError("Interpolation input value falls outside table definition range"));
+            }
+#endif
+        }
+
+    public:
+
+        /*! \brief Default tolerance for cubic spline tables
+         *
+         * This is 10*GMX_FLOAT_EPS in single precision, and
+         * 1e-10 for double precision. It might not be worth setting
+         * this tolerance lower than 1e-10 in double precision, both because
+         * you will end up with very large tables, and because
+         * functions like r^-12 become so large for small values of r the
+         * table generation code will lead to some precision loss even
+         * in double precision.
+         */
+        static const real defaultTolerance;
+
+        /*! \brief Initialize table data from function
+         *
+         * \param analyticalInputList Initializer list with one or more functions to tabulate,
+         *                            specified as elements with a string description and
+         *                            the function as well as derivative. The function will also
+         *                            be called for values smaller than the lower limit of the
+         *                            range, but we avoid calling it for 0.0 if that value
+         *                            is not included in the range.
+         *                            Constructor will throw gmx::APIError for negative values.
+         *                            Due to the way the numerical derivative evaluation depends
+         *                            on machine precision internally, this range must be
+         *                            at least 0.001, or the constructor throws gmx::APIError.
+         * \param range                Range over which the function will be tabulated.
+         *                             Constructor will throw gmx::APIError for negative values,
+         *                             or if the value/derivative vector does not cover the
+         *                             range.
+         * \param tolerance           Requested accuracy of the table. This will be used to
+         *                            calculate the required internal spacing. If this cannot
+         *                            be achieved (for instance because the table would require
+         *                            too much memory) the constructor will throw gmx::ToleranceError.
+         *
+         * \note The functions are always defined in double precision to avoid
+         *       losing accuracy when constructing tables.
+         *
+         * \note Since we fill the table for values below range.first, you can achieve
+         *       a smaller table by using a smaller range where the tolerance has to be
+         *       met, and accept that a few function calls below range.first do not
+         *       quite reach the tolerance.
+         *
+         * \warning For efficiency reasons (since this code is used in some inner
+         *       (kernels), we always allocate memory and calculate table indices
+         *       for the complete interval [0,range.second], although the data will
+         *       not be valid outside the definition range to avoid calling the
+         *       function there. This means you should \a not use this class
+         *       to tabulate functions for small ranges very far away from zero,
+         *       since you would both waste a huge amount of memory and incur
+         *       truncation errors when calculating the index.
+         *
+         * \throws gmx::ToleranceError if the requested tolerance cannot be achieved,
+         *         and gmx::APIError for other incorrect input.
+         */
+        CubicSplineTable(std::initializer_list<AnalyticalSplineTableInput>  analyticalInputList,
+                         const std::pair<real, real>                       &range,
+                         real                                               tolerance = defaultTolerance);
+
+        /*! \brief Initialize table data from tabulated values and derivatives
+         *
+         * \param numericalInputList  Initializer list with one or more functions to tabulate,
+         *                            specified as a string description, vectors with function and
+         *                            derivative values, and the input spacing. Data points are
+         *                            separated by the spacing parameter, starting from 0.
+         *                            Values below the lower limit of the range will be used to
+         *                            attempt defining the table, but we avoid using index 0
+         *                            unless 0.0 is included in the range. Some extra points beyond
+         *                            range.second are required to re-interpolate values, so add
+         *                            some margin. The constructor will throw gmx::APIError if the
+         *                            input vectors are too short to cover the requested range
+         *                            (and they must always be at least five points).
+         * \param range               Range over which the function will be tabulated.
+         *                            Constructor will throw gmx::APIError for negative values,
+         *                            or if the value/derivative vector does not cover the
+         *                            range.
+         * \param tolerance           Requested accuracy of the table. This will be used to
+         *                            calculate the required internal spacing and possibly
+         *                            re-interpolate. The constructor will throw
+         *                            gmx::ToleranceError if the input spacing is too coarse
+         *                            to achieve this accuracy.
+         *
+         * \note The input data vectors are always double precision to avoid
+         *       losing accuracy when constructing tables.
+         *
+         * \note Since we fill the table for values below range.first, you can achieve
+         *       a smaller table by using a smaller range where the tolerance has to be
+         *       met, and accept that a few function calls below range.first do not
+         *       quite reach the tolerance.
+         *
+         * \warning For efficiency reasons (since this code is used in some inner
+         *       (kernels), we always allocate memory and calculate table indices
+         *       for the complete interval [0,range.second], although the data will
+         *       not be valid outside the definition range to avoid calling the
+         *       function there. This means you should \a not use this class
+         *       to tabulate functions for small ranges very far away from zero,
+         *       since you would both waste a huge amount of memory and incur
+         *       truncation errors when calculating the index.
+         */
+        CubicSplineTable(std::initializer_list<NumericalSplineTableInput>  numericalInputList,
+                         const std::pair<real, real>                      &range,
+                         real                                              tolerance = defaultTolerance);
+
+
+        /************************************************************
+         *           Evaluation methods for single functions        *
+         ************************************************************/
+
+        /*! \brief Evaluate both function and derivative, single table function
+         *
+         *  This is a templated method where the template can be either real or SimdReal.
+         *
+         *  \tparam     numFuncInTable  Number of separate functions in table, default is 1
+         *  \tparam     funcIndex       Index of function to evaluate in table, default is 0
+         *  \tparam     T               Type (SimdReal or real) of lookup and result
+         *  \param      r               Points for which to evaluate function and derivative
+         *  \param[out] functionValue   Function value
+         *  \param[out] derivativeValue Function derivative
+         *
+         *  For debug builds we assert that the input values fall in the range
+         *  specified when constructing the table.
+         */
+        template <int numFuncInTable = 1, int funcIndex = 0, typename T>
+        void
+        evaluateFunctionAndDerivative(T     r,
+                                      T *   functionValue,
+                                      T *   derivativeValue) const
+        {
+            rangeCheck(r);
+            GMX_ASSERT(numFuncInTable == numFuncInTable_, "Evaluation method not matching number of functions in table");
+            GMX_ASSERT(funcIndex < numFuncInTable, "Function index not in range of the number of tables");
+
+            T     rTable   = r * T(tableScale_);
+            auto  tabIndex = cvttR2I(rTable); // type is either std::int32_t or SimdInt32
+            T     eps      = rTable - trunc(rTable);
+            T     Y, F, G, H;
+
+            // Load Derivative, Delta, Function, and Zero values for each table point.
+            // The 4 refers to these four values - not any SIMD width.
+            gatherLoadBySimdIntTranspose<4*numFuncInTable>(yfghMultiTableData_.data() + 4*funcIndex, tabIndex, &Y, &F, &G, &H);
+            *functionValue   = fma(fma(fma(H, eps, G), eps, F), eps, Y);
+            *derivativeValue = tableScale_ * fma(fma(T(3.0)*H, eps, T(2.0)*G), eps, F);
+        }
+
+        /*! \brief Evaluate function value only, single table function
+         *
+         *  This is a templated method where the template can be either real or SimdReal.
+         *
+         *  \tparam     numFuncInTable  Number of separate functions in table, default is 1
+         *  \tparam     funcIndex       Index of function to evaluate in table, default is 0
+         *  \tparam     T               Type (SimdReal or real) of lookup and result
+         *  \param      r               Points for which to evaluate function value
+         *  \param[out] functionValue   Function value
+         *
+         *  For debug builds we assert that the input values fall in the range
+         *  specified when constructing the table.
+         */
+        template <int numFuncInTable = 1, int funcIndex = 0, typename T>
+        void
+        evaluateFunction(T     r,
+                         T *   functionValue) const
+        {
+            T     der gmx_unused;
+
+            evaluateFunctionAndDerivative<numFuncInTable, funcIndex>(r, functionValue, &der);
+        }
+
+        /*! \brief Evaluate function derivative only, single table function
+         *
+         *  This is a templated method where the template can be either real or SimdReal.
+         *
+         *  \tparam     numFuncInTable  Number of separate functions in table, default is 1
+         *  \tparam     funcIndex       Index of function to evaluate in table, default is 0
+         *  \tparam     T               Type (SimdReal or real) of lookup and result
+         *  \param      r               Points for which to evaluate function derivative
+         *  \param[out] derivativeValue Function derivative
+         *
+         *  For debug builds we assert that the input values fall in the range
+         *  specified when constructing the table.
+         */
+        template <int numFuncInTable = 1, int funcIndex = 0, typename T>
+        void
+        evaluateDerivative(T     r,
+                           T *   derivativeValue) const
+        {
+            rangeCheck(r);
+            GMX_ASSERT(numFuncInTable == numFuncInTable_, "Evaluation method not matching number of functions in table");
+            GMX_ASSERT(funcIndex < numFuncInTable, "Function index not in range of the number of tables");
+
+            T     rTable   = r * T(tableScale_);
+            auto  tabIndex = cvttR2I(rTable); // type is either std::int32_t or SimdInt32
+            T     eps      = rTable - trunc(rTable);
+            T     Y, F, G, H;
+
+            // Load Derivative, Delta, Function, and Zero values for each table point.
+            // The 4 refers to these four values - not any SIMD width.
+            gatherLoadBySimdIntTranspose<4*numFuncInTable>(yfghMultiTableData_.data() + 4 * funcIndex, tabIndex, &Y, &F, &G, &H);
+            *derivativeValue = tableScale_ * fma(fma(T(3.0)*H, eps, T(2.0)*G), eps, F);
+        }
+
+        /************************************************************
+         *             Evaluation methods for two functions         *
+         ************************************************************/
+
+        /*! \brief Evaluate both function and derivative, two table functions
+         *
+         *  This is a templated method where the template can be either real or SimdReal.
+         *
+         *  \tparam     numFuncInTable  Number of separate functions in table, default is 2
+         *  \tparam     funcIndex0       Index of 1st function to evaluate in table, default is 0
+         *  \tparam     funcIndex1       Index of 2nd function to evaluate in table, default is 1
+         *  \tparam     T                Type (SimdReal or real) of lookup and result
+         *  \param      r                Points for which to evaluate function and derivative
+         *  \param[out] functionValue0   Interpolated value for first function
+         *  \param[out] derivativeValue0 Interpolated derivative for first function
+         *  \param[out] functionValue1   Interpolated value for second function
+         *  \param[out] derivativeValue1 Interpolated derivative for second function
+         *
+         *  For debug builds we assert that the input values fall in the range
+         *  specified when constructing the table.
+         */
+        template <int numFuncInTable = 2, int funcIndex0 = 0, int funcIndex1 = 1, typename T>
+        void
+        evaluateFunctionAndDerivative(T     r,
+                                      T *   functionValue0,
+                                      T *   derivativeValue0,
+                                      T *   functionValue1,
+                                      T *   derivativeValue1) const
+        {
+            rangeCheck(r);
+            GMX_ASSERT(numFuncInTable == numFuncInTable_, "Evaluation method not matching number of functions in table");
+            GMX_ASSERT(funcIndex0 < numFuncInTable && funcIndex1 < numFuncInTable, "Function index not in range of the number of tables");
+
+            T     rTable   = r * T(tableScale_);
+            auto  tabIndex = cvttR2I(rTable); // type is either std::int32_t or SimdInt32
+            T     eps      = rTable - trunc(rTable);
+            T     Y, F, G, H;
+
+            // Load Derivative, Delta, Function, and Zero values for each table point.
+            // The 4 refers to these four values - not any SIMD width.
+            gatherLoadBySimdIntTranspose<4*numFuncInTable>(yfghMultiTableData_.data() + 4*funcIndex0, tabIndex, &Y, &F, &G, &H);
+            *functionValue0   = fma(fma(fma(H, eps, G), eps, F), eps, Y);
+            *derivativeValue0 = tableScale_ * fma(fma(T(3.0)*H, eps, T(2.0)*G), eps, F);
+
+            gatherLoadBySimdIntTranspose<4*numFuncInTable>(yfghMultiTableData_.data() + 4*funcIndex1, tabIndex, &Y, &F, &G, &H);
+            *functionValue1   = fma(fma(fma(H, eps, G), eps, F), eps, Y);
+            *derivativeValue1 = tableScale_ * fma(fma(T(3.0)*H, eps, T(2.0)*G), eps, F);
+        }
+
+        /*! \brief Evaluate function value only, two table functions
+         *
+         *  This is a templated method where the template can be either real or SimdReal.
+         *
+         *  \tparam     numFuncInTable   Number of separate functions in table, default is 2
+         *  \tparam     funcIndex0       Index of 1st function to evaluate in table, default is 0
+         *  \tparam     funcIndex1       Index of 2nd function to evaluate in table, default is 1
+         *  \tparam     T                Type (SimdReal or real) of lookup and result
+         *  \param      r                Points for which to evaluate function value
+         *  \param[out] functionValue0   Interpolated value for first function
+         *  \param[out] functionValue1   Interpolated value for second function
+         *
+         *  For debug builds we assert that the input values fall in the range
+         *  specified when constructing the table.
+         */
+        template <int numFuncInTable = 2, int funcIndex0 = 0, int funcIndex1 = 1, typename T>
+        void
+        evaluateFunction(T     r,
+                         T *   functionValue0,
+                         T *   functionValue1) const
+        {
+            T     der0 gmx_unused;
+            T     der1 gmx_unused;
+
+            evaluateFunctionAndDerivative<numFuncInTable, funcIndex0, funcIndex1>(r, functionValue0, &der0, functionValue1, &der1);
+        }
+
+        /*! \brief Evaluate function derivative only, two table functions
+         *
+         *  This is a templated method where the template can be either real or SimdReal.
+         *
+         *  \tparam     numFuncInTable   Number of separate functions in table, default is 2
+         *  \tparam     funcIndex0       Index of 1st function to evaluate in table, default is 0
+         *  \tparam     funcIndex1       Index of 2nd function to evaluate in table, default is 1
+         *  \tparam     T                Type (SimdReal or real) of lookup and result
+         *  \param      r                Points for which to evaluate function derivative
+         *  \param[out] derivativeValue0 Interpolated derivative for first function
+         *  \param[out] derivativeValue1 Interpolated derivative for second function
+         *
+         *  For debug builds we assert that the input values fall in the range
+         *  specified when constructing the table.
+         */
+        template <int numFuncInTable = 2, int funcIndex0 = 0, int funcIndex1 = 1, typename T>
+        void
+        evaluateDerivative(T     r,
+                           T *   derivativeValue0,
+                           T *   derivativeValue1) const
+        {
+            rangeCheck(r);
+            GMX_ASSERT(numFuncInTable == numFuncInTable_, "Evaluation method not matching number of functions in table");
+            GMX_ASSERT(funcIndex0 < numFuncInTable && funcIndex1 < numFuncInTable, "Function index not in range of the number of tables");
+
+            T     rTable   = r * T(tableScale_);
+            auto  tabIndex = cvttR2I(rTable); // type is either std::int32_t or SimdInt32
+            T     eps      = rTable - trunc(rTable);
+            T     Y, F, G, H;
+
+            // Load Derivative, Delta, Function, and Zero values for each table point.
+            // The 4 refers to these four values - not any SIMD width.
+            gatherLoadBySimdIntTranspose<4*numFuncInTable>(yfghMultiTableData_.data() + 4 * funcIndex0, tabIndex, &Y, &F, &G, &H);
+            *derivativeValue0 = tableScale_ * fma(fma(T(3.0)*H, eps, T(2.0)*G), eps, F);
+
+            gatherLoadBySimdIntTranspose<4*numFuncInTable>(yfghMultiTableData_.data() + 4 * funcIndex1, tabIndex, &Y, &F, &G, &H);
+            *derivativeValue1 = tableScale_ * fma(fma(T(3.0)*H, eps, T(2.0)*G), eps, F);
+        }
+
+        /************************************************************
+         *            Evaluation methods for three functions        *
+         ************************************************************/
+
+
+        /*! \brief Evaluate both function and derivative, three table functions
+         *
+         *  This is a templated method where the template can be either real or SimdReal.
+         *
+         *  \tparam     numFuncInTable   Number of separate functions in table, default is 3
+         *  \tparam     funcIndex0       Index of 1st function to evaluate in table, default is 0
+         *  \tparam     funcIndex1       Index of 2nd function to evaluate in table, default is 1
+         *  \tparam     funcIndex2       Index of 3rd function to evaluate in table, default is 2
+         *  \tparam     T                Type (SimdReal or real) of lookup and result
+         *  \param      r                Points for which to evaluate function and derivative
+         *  \param[out] functionValue0   Interpolated value for first function
+         *  \param[out] derivativeValue0 Interpolated derivative for first function
+         *  \param[out] functionValue1   Interpolated value for second function
+         *  \param[out] derivativeValue1 Interpolated derivative for second function
+         *  \param[out] functionValue2   Interpolated value for third function
+         *  \param[out] derivativeValue2 Interpolated derivative for third function
+         *
+         *  For debug builds we assert that the input values fall in the range
+         *  specified when constructing the table.
+         */
+        template <int numFuncInTable = 3, int funcIndex0 = 0, int funcIndex1 = 1, int funcIndex2 = 2, typename T>
+        void
+        evaluateFunctionAndDerivative(T     r,
+                                      T *   functionValue0,
+                                      T *   derivativeValue0,
+                                      T *   functionValue1,
+                                      T *   derivativeValue1,
+                                      T *   functionValue2,
+                                      T *   derivativeValue2) const
+        {
+            rangeCheck(r);
+            GMX_ASSERT(numFuncInTable == numFuncInTable_, "Evaluation method not matching number of functions in table");
+            GMX_ASSERT(funcIndex0 < numFuncInTable && funcIndex1 < numFuncInTable && funcIndex2 < numFuncInTable, "Function index not in range of the number of tables");
+
+            T     rTable   = r * T(tableScale_);
+            auto  tabIndex = cvttR2I(rTable); // type is either std::int32_t or SimdInt32
+            T     eps      = rTable - trunc(rTable);
+            T     Y, F, G, H;
+
+            // Load Derivative, Delta, Function, and Zero values for each table point.
+            // The 4 refers to these four values - not any SIMD width.
+            gatherLoadBySimdIntTranspose<4*numFuncInTable>(yfghMultiTableData_.data() + 4*funcIndex0, tabIndex, &Y, &F, &G, &H);
+            *functionValue0   = fma(fma(fma(H, eps, G), eps, F), eps, Y);
+            *derivativeValue0 = tableScale_ * fma(fma(T(3.0)*H, eps, T(2.0)*G), eps, F);
+
+            gatherLoadBySimdIntTranspose<4*numFuncInTable>(yfghMultiTableData_.data() + 4*funcIndex1, tabIndex, &Y, &F, &G, &H);
+            *functionValue1   = fma(fma(fma(H, eps, G), eps, F), eps, Y);
+            *derivativeValue1 = tableScale_ * fma(fma(T(3.0)*H, eps, T(2.0)*G), eps, F);
+
+            gatherLoadBySimdIntTranspose<4*numFuncInTable>(yfghMultiTableData_.data() + 4*funcIndex2, tabIndex, &Y, &F, &G, &H);
+            *functionValue2   = fma(fma(fma(H, eps, G), eps, F), eps, Y);
+            *derivativeValue2 = tableScale_ * fma(fma(T(3.0)*H, eps, T(2.0)*G), eps, F);
+        }
+
+        /*! \brief Evaluate function value only, three table functions
+         *
+         *  This is a templated method where the template can be either real or SimdReal.
+         *
+         *  \tparam     numFuncInTable   Number of separate functions in table, default is 3
+         *  \tparam     funcIndex0       Index of 1st function to evaluate in table, default is 0
+         *  \tparam     funcIndex1       Index of 2nd function to evaluate in table, default is 1
+         *  \tparam     funcIndex2       Index of 3rd function to evaluate in table, default is 2
+         *  \tparam     T                Type (SimdReal or real) of lookup and result
+         *  \param      r                Points for which to evaluate function value
+         *  \param[out] functionValue0   Interpolated value for first function
+         *  \param[out] functionValue1   Interpolated value for second function
+         *  \param[out] functionValue2   Interpolated value for third function
+         *
+         *  For debug builds we assert that the input values fall in the range
+         *  specified when constructing the table.
+         */
+        template <int numFuncInTable = 3, int funcIndex0 = 0, int funcIndex1 = 1, int funcIndex2 = 2, typename T>
+        void
+        evaluateFunction(T     r,
+                         T *   functionValue0,
+                         T *   functionValue1,
+                         T *   functionValue2) const
+        {
+            T     der0 gmx_unused;
+            T     der1 gmx_unused;
+            T     der2 gmx_unused;
+
+            evaluateFunctionAndDerivative<numFuncInTable, funcIndex0, funcIndex1, funcIndex2>(r, functionValue0, &der0, functionValue1, &der1, functionValue2, &der2);
+        }
+
+        /*! \brief Evaluate function derivative only, three table functions
+         *
+         *  This is a templated method where the template can be either real or SimdReal.
+         *
+         *  \tparam     numFuncInTable   Number of separate functions in table, default is 3
+         *  \tparam     funcIndex0       Index of 1st function to evaluate in table, default is 0
+         *  \tparam     funcIndex1       Index of 2nd function to evaluate in table, default is 1
+         *  \tparam     funcIndex2       Index of 3rd function to evaluate in table, default is 2
+         *  \tparam     T                Type (SimdReal or real) of lookup and result
+         *  \param      r                Points for which to evaluate function derivative
+         *  \param[out] derivativeValue0 Interpolated derivative for first function
+         *  \param[out] derivativeValue1 Interpolated derivative for second function
+         *  \param[out] derivativeValue2 Interpolated derivative for third function
+         *
+         *  For debug builds we assert that the input values fall in the range
+         *  specified when constructing the table.
+         */
+        template <int numFuncInTable = 3, int funcIndex0 = 0, int funcIndex1 = 1, int funcIndex2 = 2, typename T>
+        void
+        evaluateDerivative(T     r,
+                           T *   derivativeValue0,
+                           T *   derivativeValue1,
+                           T *   derivativeValue2) const
+        {
+            rangeCheck(r);
+            GMX_ASSERT(numFuncInTable == numFuncInTable_, "Evaluation method not matching number of functions in table");
+            GMX_ASSERT(funcIndex0 < numFuncInTable && funcIndex1 < numFuncInTable && funcIndex2 < numFuncInTable, "Function index not in range of the number of tables");
+
+            T     rTable   = r * T(tableScale_);
+            auto  tabIndex = cvttR2I(rTable); // type is either std::int32_t or SimdInt32
+            T     eps      = rTable - trunc(rTable);
+            T     Y, F, G, H;
+
+            // Load Derivative, Delta, Function, and Zero values for each table point.
+            // The 4 refers to these four values - not any SIMD width.
+            gatherLoadBySimdIntTranspose<4*numFuncInTable>(yfghMultiTableData_.data() + 4 * funcIndex0, tabIndex, &Y, &F, &G, &H);
+            *derivativeValue0 = tableScale_ * fma(fma(T(3.0)*H, eps, T(2.0)*G), eps, F);
+
+            gatherLoadBySimdIntTranspose<4*numFuncInTable>(yfghMultiTableData_.data() + 4 * funcIndex1, tabIndex, &Y, &F, &G, &H);
+            *derivativeValue1 = tableScale_ * fma(fma(T(3.0)*H, eps, T(2.0)*G), eps, F);
+
+            gatherLoadBySimdIntTranspose<4*numFuncInTable>(yfghMultiTableData_.data() + 4 * funcIndex2, tabIndex, &Y, &F, &G, &H);
+            *derivativeValue2 = tableScale_ * fma(fma(T(3.0)*H, eps, T(2.0)*G), eps, F);
+        }
+
+        /*! \brief Return the table spacing (distance between points)
+         *
+         *  You should never have to use this for normal code, but due to the
+         *  way tables are constructed internally we need this in the unit tests
+         *  to check relative tolerances over each interval.
+         *
+         *  \return table spacing.
+         */
+        real
+        tableSpacing() const { return 1.0 / tableScale_; }
+
+    private:
+
+        std::size_t             numFuncInTable_; //!< Number of separate tabluated functions
+        std::pair<real, real>   range_;          //!< Range for which table evaluation is allowed
+        real                    tableScale_;     //!< Table scale (inverse of spacing between points)
+
+        /*! \brief Vector with combined table data to save calculations after lookup.
+         *
+         *  For table point i, this vector contains the four coefficients
+         *  Y,F,G,H that we use to express the function value as
+         *  V(x)  = Y + F e + G e^2 + H e^3, where e is the epsilon offset from
+         *  the nearest table point.
+         *
+         *  To allow aligned SIMD loads we need to use an aligned allocator for
+         *  this container.
+         */
+        std::vector<real, AlignedAllocator<real> >  yfghMultiTableData_;
+
+        // There should never be any reason to copy the table since it is read-only
+        GMX_DISALLOW_COPY_AND_ASSIGN(CubicSplineTable);
+};
+
+
+}      // namespace gmx
+
+#endif // GMX_TABLES_CUBICSPLINETABLE_H
index 9236b344057acce92dfd6264182329f8858cbb73..d2ca216357b9ad5a9fcbac75cb308d9ce3ac28bc 100644 (file)
 #ifndef GMX_TABLES_FORCETABLE_H
 #define GMX_TABLES_FORCETABLE_H
 
+/*! \libinternal \file
+ * \brief
+ * Old routines for table generation (will eventually be replaced)
+ *
+ * \inlibraryapi
+ * \author Erik Lindahl <erik.lindahl@gmail.com>
+ * \ingroup module_tables
+ */
+
 #include <cstdio>
 
 #include "gromacs/mdtypes/fcdata.h"
 #include "gromacs/mdtypes/interaction_const.h"
 #include "gromacs/utility/real.h"
 
+/*! \brief Flag to select user tables for make_tables */
 #define GMX_MAKETABLES_FORCEUSER  (1<<0)
+/*! \brief Flag to only make 1,4 pair tables for make_tables */
 #define GMX_MAKETABLES_14ONLY     (1<<1)
 
-/* Index in the tables that says which function to use */
+/*! \brief Enumerated type to describe the interaction types in a table */
 enum {
-    etiCOUL, etiLJ6, etiLJ12, etiNR
+    etiCOUL,  //!< Coulomb
+    etiLJ6,   //!< Dispersion
+    etiLJ12,  //!< Repulsion
+    etiNR     //!< Total number of interaction types
 };
 
-typedef double (*real_space_grid_contribution_computer)(double, double);
-/* Function pointer used to tell table_spline3_fill_ewald_lr whether it
+/*! \brief Function pointer to calculate the grid contribution for coulomb/LJ
+ *
+ * Used to tell table_spline3_fill_ewald_lr whether it
  * should calculate the grid contribution for electrostatics or LJ.
  */
+typedef double (*real_space_grid_contribution_computer)(double, double);
+
 
+/*! \brief Fill tables with the Ewald long-range force interaction
+ *
+ * Fill tables of ntab points with spacing dr with the ewald long-range
+ * (mesh) force.
+ * There are three separate tables with format FDV0, F, and V.
+ * This function interpolates the Ewald mesh potential contribution
+ * with coefficient beta using a quadratic spline.
+ * The force can then be interpolated linearly.
+ *
+ * \param table_F    Force table
+ * \param table_V    Potential table
+ * \param table_FDV0 Combined table optimized for SIMD loads
+ * \param ntab       Number of points in tables
+ * \param dx         Spacing
+ * \param beta       Ewald splitting paramter
+ * \param v_lr       Pointer to function calculating real-space grid contribution
+ */
 void table_spline3_fill_ewald_lr(real                                 *table_F,
                                  real                                 *table_V,
                                  real                                 *table_FDV0,
@@ -62,34 +96,58 @@ void table_spline3_fill_ewald_lr(real                                 *table_F,
                                  double                                dx,
                                  real                                  beta,
                                  real_space_grid_contribution_computer v_lr);
-/* Fill tables of ntab points with spacing dr with the ewald long-range
- * (mesh) force.
- * There are three separate tables with format FDV0, F, and V.
- * This function interpolates the Ewald mesh potential contribution
- * with coefficient beta using a quadratic spline.
- * The force can then be interpolated linearly.
- */
 
+/*! \brief Compute scaling for the Ewald quadratic spline tables.
+ *
+ * \param ic  Pointer to interaction constant structure
+ * \return The scaling factor
+ */
 real ewald_spline3_table_scale(const interaction_const_t *ic);
-/* Return the scaling for the Ewald quadratic spline tables. */
 
+/*! \brief Return the real space grid contribution for Ewald
+ *
+ *  \param beta  Ewald splitting parameter
+ *  \param r     Distance for which to calculate the real-space contrib
+ *  \return      Real space grid contribution for Ewald electrostatics
+ */
 double v_q_ewald_lr(double beta, double r);
-/* Return the real space grid contribution for Ewald*/
 
+/*! \brief Return the real space grid contribution for LJ-Ewald
+ *
+ *  \param beta  Ewald splitting parameter
+ *  \param r     Distance for which to calculate the real-space contrib
+ *  \return      Real space grid contribution for Ewald Lennard-Jones interaction
+ */
 double v_lj_ewald_lr(double beta, double r);
-/* Return the real space grid contribution for LJ-Ewald*/
 
+/*! \brief Return tables for inner loops.
+ *
+ * \param fp     Log file pointer
+ * \param fr     Force record
+ * \param fn     File name from which to read user tables
+ * \param rtab   Largest interaction distance to tabulate
+ * \param flags  Flags to select table settings
+ *
+ * \return Pointer to inner loop table structure
+ */
 t_forcetable *make_tables(FILE *fp,
                           const t_forcerec *fr,
                           const char *fn, real rtab, int flags);
-/* Return tables for inner loops. */
 
-bondedtable_t make_bonded_table(FILE *fplog, const char *fn, int angle);
-/* Return a table for bonded interactions,
- * angle should be: bonds 0, angles 1, dihedrals 2
+/*! \brief Return a table for bonded interactions,
+ *
+ * \param  fplog   Pointer to log file
+ * \param  fn      File name
+ * \param  angle   Type of angle: bonds 0, angles 1, dihedrals 2
+ * \return New bonded table datatype
  */
+bondedtable_t make_bonded_table(FILE *fplog, const char *fn, int angle);
 
-/* Return a table for GB calculations */
+/*! \brief Return a table for GB calculations
+ *
+ * \param fr   Force record
+ * \return     Pointer to new gb table structure
+ */
 t_forcetable *make_gb_table(const t_forcerec              *fr);
 
 /*! \brief Construct and return tabulated dispersion and repulsion interactions
diff --git a/src/gromacs/tables/quadraticsplinetable.cpp b/src/gromacs/tables/quadraticsplinetable.cpp
new file mode 100644 (file)
index 0000000..94dc2b3
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+
+/*! \internal \file
+ * \brief
+ * Implements classes for quadratic spline table functions
+ *
+ * \author Erik Lindahl <erik.lindahl@gmail.com>
+ * \ingroup module_tables
+ */
+#include "gmxpre.h"
+
+#include "quadraticsplinetable.h"
+
+#include <cmath>
+
+#include <algorithm>
+#include <functional>
+#include <initializer_list>
+#include <utility>
+#include <vector>
+
+#include "gromacs/tables/tableinput.h"
+#include "gromacs/utility/alignedallocator.h"
+#include "gromacs/utility/arrayref.h"
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/real.h"
+
+#include "splineutil.h"
+
+namespace gmx
+{
+
+namespace
+{
+
+/*! \brief Construct the data for a single quadratic table from analytical functions
+ *
+ * \param[in]  function             Analytical functiojn
+ * \param[in]  derivative           Analytical derivative
+ * \param[in]  range                Upper/lower limit of region to tabulate
+ * \param[in]  spacing              Distance between table points
+ * \param[out] functionTableData    Output table with function data
+ * \param[out] derivativeTableData  OUtput table with (adjusted) derivative data
+ */
+void
+fillSingleQuadraticSplineTableData(const std::function<double(double)>   &function,
+                                   const std::function<double(double)>   &derivative,
+                                   const std::pair<real, real>           &range,
+                                   double                                 spacing,
+                                   std::vector<real>                     *functionTableData,
+                                   std::vector<real>                     *derivativeTableData)
+{
+    std::size_t  endIndex   = range.second / spacing + 2;
+
+    functionTableData->resize(endIndex);
+    derivativeTableData->resize(endIndex);
+
+    double       maxMagnitude      = 0.0001*GMX_REAL_MAX;
+    bool         functionIsInRange = true;
+    std::size_t  lastIndexInRange  = endIndex - 1;
+
+    for (int i = endIndex - 1; i >= 0; i--)
+    {
+        double x                = i * spacing;
+        double tmpFunctionValue;
+        double tmpDerivativeValue;
+
+        if (range.first > 0 && i == 0)
+        {
+            // Avoid x==0 if it is not in the range, since it can lead to
+            // singularities even if the value for i==1 was within or required magnitude
+            functionIsInRange = false;
+        }
+
+        if (functionIsInRange)
+        {
+            tmpFunctionValue = function(x);
+
+            // Calculate third derivative term (2nd derivative of the derivative)
+            // Make sure we stay in range. In practice this means we use one-sided
+            // interpolation at the interval endpoints (indentical to an offset for 3-point formula)
+            const double h                    = std::pow( GMX_DOUBLE_EPS, 0.25 );
+            double       y                    = std::min( std::max(x, range.first + h), range.second - h);
+            double       thirdDerivativeValue = ( derivative(y+h) - 2.0 * derivative(y) + derivative(y-h) ) / ( h * h );
+
+            tmpDerivativeValue   = derivative(x) - spacing * spacing * thirdDerivativeValue / 12.0;
+
+            if (std::abs(tmpFunctionValue) > maxMagnitude || std::abs(tmpDerivativeValue) > maxMagnitude)
+            {
+                functionIsInRange = false; // Once this happens, it never resets to true again
+            }
+        }
+
+        if (functionIsInRange)
+        {
+            (*functionTableData)[i]   = tmpFunctionValue;
+            (*derivativeTableData)[i] = tmpDerivativeValue;
+            lastIndexInRange--;
+        }
+        else
+        {
+            // Once the function or derivative (more likely) has reached very large values,
+            // we simply make a linear function from the last in-range value of the derivative.
+            double lastIndexFunction   = (*functionTableData)[lastIndexInRange];
+            double lastIndexDerivative = (*derivativeTableData)[lastIndexInRange];
+            (*functionTableData)[i]    = lastIndexFunction + lastIndexDerivative * (i - lastIndexInRange) * spacing;
+            (*derivativeTableData)[i]  = lastIndexDerivative;
+        }
+    }
+}
+
+
+/*! \brief Construct the data for a single quadratic table from vector data
+ *
+ * \param[in]  function             Input vector with function data
+ * \param[in]  derivative           Input vector with derivative data
+ * \param[in]  inputSpacing         Distance between points in input vectors
+ * \param[in]  range                Upper/lower limit of region to tabulate
+ * \param[in]  spacing              Distance between table points
+ * \param[out] functionTableData    Output table with function data
+ * \param[out] derivativeTableData  OUtput table with (adjusted) derivative data
+ */
+void
+fillSingleQuadraticSplineTableData(ConstArrayRef<double>                  function,
+                                   ConstArrayRef<double>                  derivative,
+                                   double                                 inputSpacing,
+                                   const std::pair<real, real>           &range,
+                                   double                                 spacing,
+                                   std::vector<real>                     *functionTableData,
+                                   std::vector<real>                     *derivativeTableData)
+{
+    std::size_t  endIndex   = range.second / spacing + 2;
+
+    functionTableData->resize(endIndex);
+    derivativeTableData->resize(endIndex);
+
+    std::vector<double>  thirdDerivative(internal::vectorSecondDerivative(derivative, inputSpacing));
+
+    double               maxMagnitude      = 0.0001*GMX_REAL_MAX;
+    bool                 functionIsInRange = true;
+    std::size_t          lastIndexInRange  = endIndex - 1;
+
+    for (int i = endIndex - 1; i >= 0; i--)
+    {
+        double x                = i * spacing;
+        double tmpFunctionValue;
+        double tmpDerivativeValue;
+
+        if (range.first > 0 && i == 0)
+        {
+            // Avoid x==0 if it is not in the range, since it can lead to
+            // singularities even if the value for i==1 was within or required magnitude
+            functionIsInRange = false;
+        }
+
+        if (functionIsInRange)
+        {
+            // Step 1: Interpolate the function value at x from input table.
+            double inputXTab  = x / inputSpacing;
+            int    inputIndex = inputXTab;
+            double inputEps   = inputXTab - inputIndex;
+
+            // Linear interpolation of input derivative and third derivative
+            double thirdDerivativeValue = (1.0 - inputEps) * thirdDerivative[inputIndex] + inputEps * thirdDerivative[inputIndex+1];
+            double derivativeValue      = (1.0 - inputEps) *      derivative[inputIndex] + inputEps *      derivative[inputIndex+1];
+
+            // Quadratic interpolation for function value
+            tmpFunctionValue     = function[inputIndex] + 0.5 * (derivative[inputIndex] + derivativeValue) * inputEps * inputSpacing;
+            tmpDerivativeValue   = derivativeValue - spacing * spacing * thirdDerivativeValue / 12.0;
+
+            if (std::abs(tmpFunctionValue) > maxMagnitude || std::abs(tmpDerivativeValue) > maxMagnitude)
+            {
+                functionIsInRange = false; // Once this happens, it never resets to true again
+            }
+        }
+
+        if (functionIsInRange)
+        {
+            (*functionTableData)[i]   = tmpFunctionValue;
+            (*derivativeTableData)[i] = tmpDerivativeValue;
+            lastIndexInRange--;
+        }
+        else
+        {
+            // Once the function or derivative (more likely) has reached very large values,
+            // we simply make a linear function from the last in-range value of the derivative.
+            double lastIndexFunction   = (*functionTableData)[lastIndexInRange];
+            double lastIndexDerivative = (*derivativeTableData)[lastIndexInRange];
+            (*functionTableData)[i]    = lastIndexFunction + lastIndexDerivative * (i - lastIndexInRange) * spacing;
+            (*derivativeTableData)[i]  = lastIndexDerivative;
+        }
+    }
+}
+
+/*! \brief Create merged DDFZ vector from function & derivative data
+ *
+ *  \param functionTableData     Function values
+ *  \param derivativeTableData   Derivative values. We have already subtracted the
+ *                               small third derivative component when calling this
+ *                               function, but in practice it is just an arbitrary
+ *                               vector here.
+ *  \param ddfzTableData         Vector four times longer, filled with
+ *                               the derivative, the difference to the next derivative
+ *                               point, the function value, and zero.
+ *
+ *  \throws If the vector lengths do not match.
+ */
+void
+fillDdfzTableData(const std::vector<real>    &functionTableData,
+                  const std::vector<real>    &derivativeTableData,
+                  std::vector<real>          *ddfzTableData)
+{
+    GMX_ASSERT(functionTableData.size() == derivativeTableData.size(), "Mismatching vector lengths");
+
+    std::size_t points = functionTableData.size();
+
+    ddfzTableData->resize(4 * points);
+
+    for (std::size_t i = 0; i < points; i++)
+    {
+        (*ddfzTableData)[4*i]     = derivativeTableData[i];
+
+        double nextDerivative     = ( i < functionTableData.size() - 1 ) ? derivativeTableData[i+1] : 0.0;
+
+        (*ddfzTableData)[4*i + 1] = nextDerivative - derivativeTableData[i];
+        (*ddfzTableData)[4*i + 2] = functionTableData[i];
+        (*ddfzTableData)[4*i + 3] = 0.0;
+    }
+}
+
+}   // namespace anonymous
+
+
+
+const real
+QuadraticSplineTable::defaultTolerance = 10.0 * GMX_FLOAT_EPS;
+
+
+QuadraticSplineTable::QuadraticSplineTable(std::initializer_list<AnalyticalSplineTableInput>   analyticalInputList,
+                                           const std::pair<real, real>                        &range,
+                                           real                                                tolerance)
+    : numFuncInTable_(analyticalInputList.size()), range_(range)
+{
+    // Sanity check on input values
+    if (range_.first < 0.0 || (range_.second-range_.first) < 0.001)
+    {
+        GMX_THROW(InvalidInputError("Range to tabulate cannot include negative values and must span at least 0.001"));
+    }
+
+    if (tolerance < GMX_REAL_EPS)
+    {
+        GMX_THROW(ToleranceError("Table tolerance cannot be smaller than GMX_REAL_EPS"));
+    }
+
+    double minQuotient = GMX_REAL_MAX;
+
+    // loop over all functions to find smallest spacing
+    for (auto thisFuncInput : analyticalInputList)
+    {
+        try
+        {
+            internal::throwUnlessDerivativeIsConsistentWithFunction(thisFuncInput.function, thisFuncInput.derivative, range_);
+        }
+        catch (gmx::GromacsException &ex)
+        {
+            ex.prependContext("Error generating quadratic spline table for function '" + thisFuncInput.desc + "'");
+            throw;
+        }
+        // Calculate the required table spacing h. The error we make with linear interpolation
+        // of the derivative will be described by the third-derivative correction term.
+        // This means we can compute the required spacing as h = sqrt(12*tolerance*min(f'/f''')),
+        // where f'/f''' is the first and third derivative of the function, respectively.
+
+        double thisMinQuotient = internal::findSmallestQuotientOfFunctionAndSecondDerivative(thisFuncInput.derivative, range_);
+
+        minQuotient = std::min(minQuotient, thisMinQuotient);
+    }
+
+    double spacing = std::sqrt(12.0 * tolerance * minQuotient);
+
+    halfSpacing_ = 0.5 * spacing;
+    tableScale_  = 1.0 / spacing;
+
+    if (range_.second * tableScale_ > 1e6)
+    {
+        GMX_THROW(ToleranceError("Over a million points would be required for table; decrease range or increase tolerance"));
+    }
+
+    // Loop over all tables again.
+    // Here we create the actual table for each function, and then
+    // combine them into a multiplexed table function.
+    std::size_t funcIndex = 0;
+
+    for (auto thisFuncInput : analyticalInputList)
+    {
+        try
+        {
+            std::vector<real> tmpFuncTableData;
+            std::vector<real> tmpDerTableData;
+            std::vector<real> tmpDdfzTableData;
+
+            fillSingleQuadraticSplineTableData(thisFuncInput.function,
+                                               thisFuncInput.derivative,
+                                               range_,
+                                               spacing,
+                                               &tmpFuncTableData,
+                                               &tmpDerTableData);
+
+            fillDdfzTableData(tmpFuncTableData, tmpDerTableData, &tmpDdfzTableData);
+
+            internal::fillMultiplexedTableData(tmpDerTableData, &derivativeMultiTableData_,
+                                               1, numFuncInTable_, funcIndex);
+
+            internal::fillMultiplexedTableData(tmpDdfzTableData, &ddfzMultiTableData_,
+                                               4, numFuncInTable_, funcIndex);
+
+            funcIndex++;
+        }
+        catch (gmx::GromacsException &ex)
+        {
+            ex.prependContext("Error generating quadratic spline table for function '" + thisFuncInput.desc + "'");
+            throw;
+        }
+    }
+}
+
+
+QuadraticSplineTable::QuadraticSplineTable(std::initializer_list<NumericalSplineTableInput>   numericalInputList,
+                                           const std::pair<real, real>                       &range,
+                                           real                                               tolerance)
+    : numFuncInTable_(numericalInputList.size()), range_(range)
+{
+    // Sanity check on input values
+    if (range.first < 0.0 || (range.second-range.first) < 0.001)
+    {
+        GMX_THROW(InvalidInputError("Range to tabulate cannot include negative values and must span at least 0.001"));
+    }
+
+    if (tolerance < GMX_REAL_EPS)
+    {
+        GMX_THROW(ToleranceError("Table tolerance cannot be smaller than GMX_REAL_EPS"));
+    }
+
+    double minQuotient = GMX_REAL_MAX;
+
+    // loop over all functions to find smallest spacing
+    for (auto thisFuncInput : numericalInputList)
+    {
+        try
+        {
+            // We do not yet know what the margin is, but we need to test that we at least cover
+            // the requested range before starting to calculate derivatives
+            if (thisFuncInput.function.size() < range_.second / thisFuncInput.spacing + 1)
+            {
+                GMX_THROW(InconsistentInputError("Table input vectors must cover requested range, and a margin beyond the upper endpoint"));
+            }
+
+            if (thisFuncInput.function.size() != thisFuncInput.derivative.size())
+            {
+                GMX_THROW(InconsistentInputError("Function and derivative vectors have different lengths"));
+            }
+
+            internal::throwUnlessDerivativeIsConsistentWithFunction(thisFuncInput.function, thisFuncInput.derivative, thisFuncInput.spacing, range_);
+        }
+        catch (gmx::GromacsException &ex)
+        {
+            ex.prependContext("Error generating quadratic spline table for function '" + thisFuncInput.desc + "'");
+            throw;
+        }
+        // Calculate the required table spacing h. The error we make with linear interpolation
+        // of the derivative will be described by the third-derivative correction term.
+        // This means we can compute the required spacing as h = sqrt(12*tolerance*min(f'/f''')),
+        // where f'/f''' is the first and third derivative of the function, respectively.
+
+        double thisMinQuotient = internal::findSmallestQuotientOfFunctionAndSecondDerivative(thisFuncInput.derivative, thisFuncInput.spacing, range_);
+
+        minQuotient = std::min(minQuotient, thisMinQuotient);
+    }
+
+    double spacing     = std::sqrt(12.0 * tolerance * minQuotient);
+
+    halfSpacing_ = 0.5 * spacing;
+    tableScale_  = 1.0 / spacing;
+
+    if (range_.second * tableScale_ > 1e6)
+    {
+        GMX_THROW(ToleranceError("Requested tolerance would require over a million points in table"));
+    }
+
+    // Loop over all tables again.
+    // Here we create the actual table for each function, and then
+    // combine them into a multiplexed table function.
+    std::size_t funcIndex = 0;
+
+    for (auto thisFuncInput : numericalInputList)
+    {
+        try
+        {
+            if (spacing < thisFuncInput.spacing)
+            {
+                GMX_THROW(ToleranceError("Input vector spacing cannot achieve tolerance requested"));
+            }
+
+            std::vector<real> tmpFuncTableData;
+            std::vector<real> tmpDerTableData;
+            std::vector<real> tmpDdfzTableData;
+
+            fillSingleQuadraticSplineTableData(thisFuncInput.function,
+                                               thisFuncInput.derivative,
+                                               thisFuncInput.spacing,
+                                               range,
+                                               spacing,
+                                               &tmpFuncTableData,
+                                               &tmpDerTableData);
+
+            fillDdfzTableData(tmpFuncTableData, tmpDerTableData, &tmpDdfzTableData);
+
+            internal::fillMultiplexedTableData(tmpDerTableData, &derivativeMultiTableData_,
+                                               1, numFuncInTable_, funcIndex);
+
+            internal::fillMultiplexedTableData(tmpDdfzTableData, &ddfzMultiTableData_,
+                                               4, numFuncInTable_, funcIndex);
+
+            funcIndex++;
+        }
+        catch (gmx::GromacsException &ex)
+        {
+            ex.prependContext("Error generating quadratic spline table for function '" + thisFuncInput.desc + "'");
+            throw;
+        }
+    }
+}
+
+} // namespace gmx
diff --git a/src/gromacs/tables/quadraticsplinetable.h b/src/gromacs/tables/quadraticsplinetable.h
new file mode 100644 (file)
index 0000000..010372d
--- /dev/null
@@ -0,0 +1,748 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+
+/*! \libinternal
+ * \defgroup module_tables  Classes for table interpolation
+ * \ingroup group_utilitymodules
+ *
+ * \brief Table interpolation from analytical or numerical input
+ *
+ * This module provides quadratic spline interpolation tables used
+ * both for the nonbonded kernels and listed interactions.
+ *
+ * \author Erik Lindahl <erik.lindahl@scilifelab.se>
+ */
+
+
+/*! \libinternal \file
+ * \brief
+ * Declares classes for quadratic spline table
+ *
+ * \inlibraryapi
+ * \author Erik Lindahl <erik.lindahl@gmail.com>
+ * \ingroup module_tables
+ */
+#ifndef GMX_TABLES_QUADRATICSPLINETABLE_H
+#define GMX_TABLES_QUADRATICSPLINETABLE_H
+
+#include <functional>
+#include <initializer_list>
+#include <vector>
+
+#include "gromacs/simd/simd.h"
+#include "gromacs/tables/tableinput.h"
+#include "gromacs/utility/alignedallocator.h"
+#include "gromacs/utility/classhelpers.h"
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/real.h"
+
+namespace gmx
+{
+
+/*! \libinternal \brief Quadratic spline interpolation table.
+ *
+ * This class interpolates a function specified either as an analytical
+ * expression or from user-provided table data.
+ *
+ * At initialization, you provide the reference function of vectors
+ * as a list of tuples that contain a brief name, the function, and
+ * derivative for each function to tabulate. To create a table with
+ * two functions this initializer list can for instance look like
+ *
+ *     { {"LJ6", lj6Func, lj6Der}, {"LJ12", lj12Func, lj12Der} }
+ *
+ * The names are only used so exceptions during initialization can
+ * be traced to a specific table.
+ *
+ * When interpolating, there are methods to interpolate either 1, 2, or 3
+ * functions in one go. By default these interpolation routines will
+ * operate on tables with the same number of functions as specified in
+ * the interpolation method (debug builds check that this is consistent with
+ * the table). However, it is also possible to use optional template
+ * parameters that specify the total number of functions in a table, and
+ * what function index to interpolate. For instance, to interpolate the
+ * derivative of the second function (i.e., index 1) in a
+ * multi-function-table with three functions in total, you can write
+ *
+ *     table.evaluateDerivative<3,1>(x,&der);
+ *
+ * Here too, debug builds will check that the template parameters are
+ * consistent with the table.
+ *
+ * The table data is internally adjusted to guarantee that the interpolated
+ * derivative is the true derivative of the interpolated potential, which is
+ * important to avoid systematic errors for the common case when the derivative
+ * is concave/convex in the entire interval.
+ * We do this by expressing the difference in the function value
+ * at a small offset h relative to a reference value in position 0 with a forward
+ * Taylor series expanded around 0, and then doing the opposite of expressing
+ * difference in the function at position 0 relative to a reference value in
+ * position h when using a backward Taylor expansion:
+ *
+ * \f{eqnarray*}{
+ *  \Delta V & = & hV'(0) + \frac{1}{2} h^2 V''(0) + \frac{1}{6} h^3 V'''(0) + O(h^4) \\
+ *  \Delta V & = & hV'(h) - \frac{1}{2} h^2 V''(h) + \frac{1}{6} h^3 V'''(h) + O(h^4)
+ * \f}
+ *
+ * Summing the equations leads to
+ *
+ * \f[
+ *  2 \Delta V = h(V'(0) + V'(h)) + \frac{1}{2} h^2 (V''(0)-V''(h)) + \frac{1}{6}h^3(V'''(0)+V'''(h)) + O(h^4)
+ * \f]
+ *
+ * To make the second term symmetric too, we can replace it with the average of
+ * the Taylor expansion at 0 and h (i.e., using the third derivative). This gives
+ *
+ * \f[
+ *  2 \Delta V = h(V'(0) + V'(h)) - \frac{1}{12} h^3 (V'''(0)+V'''(h)) + O(h^4)
+ * \f]
+ *
+ * Thus, if we replace the derivative in the internal quadratic table data with
+ *
+ * \f[
+ *  V' - \frac{1}{12}h^2 V'''
+ * \f]
+ *
+ * we will cancel the h^3 term in the error. This will make the integral of the
+ * forces match the potential much better (The h^4 term actually disappears, so
+ * when summing over 1/h points the remaining error will be O(h^4).
+ *
+ * While it is possible to create tables only from function values
+ * (i.e., no derivatives), it is recommended to provide derivatives for higher
+ * accuracy and to avoid issues with numerical differentiation. Note that the
+ * table input should be smooth, i.e. it should not contain noise e.g. from an
+ * (iterative) Boltzmann inversion procedure - you have been warned.
+ *
+ * \note This class is responsible for fundamental interpolation of any function,
+ *       which might or might not correspond to a potential. For this reason
+ *       both input and output derivatives are proper function derivatives, and
+ *       we do not swap any signs to get forces directly from the table.
+ *
+ * \note There will be a small additional accuracy loss from the internal
+ *       operation where we calculate the epsilon offset from the nearest table
+ *       point, since the integer part we subtract can get large in those cases.
+ *       The absolute such error both in the function and derivative value will
+ *       be roughly f''*x*GMX_REAL_EPS, where x is the argument and f'' the
+ *       second derivative.
+ *       While this is technically possible to solve with extended precision
+ *       arithmetics, that would introduce extra instructions in some highly
+ *       performance-sensitive code parts. For typical GROMACS interaction
+ *       functions the derivatives will decay faster than the potential, which
+ *       means it will never play any role. For other functions it will only
+ *       cause a small increase in the relative error for arguments where the
+ *       magnitude of the function or derivative is very small.
+ *       Since we typically sum several results in GROMACS, this should never
+ *       show up in any real cases, and for this reason we choose not to do
+ *       the extended precision arithmetics.
+ *
+ * \note These routines are not suitable for table ranges starting far away
+ *       from zero, since we allocate memory and calculate indices starting from
+ *       range zero for efficiency reasons.
+ */
+class QuadraticSplineTable
+{
+    private:
+        /*! \brief Change that function value falls inside range when debugging
+         *
+         *  \tparam T   Lookup argument floating-point type, typically SimdReal or real.
+         *  \param  r   Lookup argument to test
+         *
+         *  \throws Debug builds will throw gmx::RangeError for values that are
+         *          larger than the upper limit of the range, or smaller than 0.
+         *          We allow the table to be called with arguments between 0 and
+         *          the lower limit of the range, since this might in theory occur
+         *          once-in-a-blue-moon with some algorithms.
+         */
+        template <typename T>
+        void
+        rangeCheck(T gmx_unused r) const
+        {
+#ifndef NDEBUG
+            // Check that all values fall in range when debugging
+            if (anyTrue( r < T(0.0) || T(range_.second) <= r ) )
+            {
+                GMX_THROW(RangeError("Interpolation input value falls outside table definition range"));
+            }
+#endif
+        }
+
+    public:
+
+        /*! \brief Default tolerance for tables is 10*GMX_FLOAT_EPS
+         *
+         *  \note Even for double precision builds we set the tolerance to
+         *        one order of magnitude above the single precision epsilon.
+         */
+        static const real defaultTolerance;
+
+        /*! \brief Initialize table data from function
+         *
+         * \param analyticalInputList Initializer list with one or more functions to tabulate,
+         *                            specified as pairs containing analytical
+         *                            functions and their derivatives. The function will also
+         *                            be called for values smaller than the lower limit of the
+         *                            range, but we avoid calling it for 0.0 if that value
+         *                            is not included in the range.
+         * \param range               Range over which the function will be tabulated.
+         *                            Constructor will throw gmx::APIError for negative values.
+         *                            Due to the way the numerical derivative evaluation depends
+         *                            on machine precision internally, this range must be
+         *                            at least 0.001, or the constructor throws gmx::APIError.
+         * \param tolerance           Requested accuracy of the table. This will be used to
+         *                            calculate the required internal spacing. If this cannot
+         *                            be achieved (for instance because the table would require
+         *                            too much memory) the constructor will throw gmx::ToleranceError.
+         *
+         * \note The functions are always defined in double precision to avoid
+         *       losing accuracy when constructing tables.
+         *
+         * \note Since we fill the table for values below range.first, you can achieve
+         *       a smaller table by using a smaller range where the tolerance has to be
+         *       met, and accept that a few function calls below range.first do not
+         *       quite reach the tolerance.
+         *
+         * \warning For efficiency reasons (since this code is used in some inner
+         *       (kernels), we always allocate memory and calculate table indices
+         *       for the complete interval [0,range.second], although the data will
+         *       not be valid outside the definition range to avoid calling the
+         *       function there. This means you should \a not use this class
+         *       to tabulate functions for small ranges very far away from zero,
+         *       since you would both waste a huge amount of memory and incur
+         *       truncation errors when calculating the index.
+         *
+         * \throws gmx::ToleranceError if the requested tolerance cannot be achieved,
+         *         and gmx::APIError for other incorrect input.
+         */
+        QuadraticSplineTable(std::initializer_list<AnalyticalSplineTableInput>   analyticalInputList,
+                             const std::pair<real, real>                        &range,
+                             real                                                tolerance = defaultTolerance);
+
+        /*! \brief Initialize table data from tabulated values and derivatives
+         *
+         * \param numericalInputList  Initializer list with one or more functions to tabulate,
+         *                            specified as pairs containing containing vectors for the
+         *                            function values and their derivatives. Data points are
+         *                            separated by the spacing parameter, starting from 0.
+         *                            Values below the lower limit of the range will be used to
+         *                            attempt defining the table, but we avoid using index 0
+         *                            unless 0.0 is included in the range. Some extra points beyond
+         *                            range.second are required to re-interpolate values, so add
+         *                            some margin. The constructor will throw gmx::APIError if the
+         *                            input vectors are too short to cover the requested range
+         *                            (and they must always be at least five points).
+         * \param range               Range over which the function will be tabulated.
+         *                            Constructor will throw gmx::APIError for negative values,
+         *                            or if the value/derivative vector does not cover the
+         *                            range.
+         * \param tolerance           Requested accuracy of the table in the range. This will be
+         *                            used to calculate the required internal spacing and possibly
+         *                            re-interpolate. The constructor will throw
+         *                            gmx::ToleranceError if the input spacing is too coarse
+         *                            to achieve this accuracy.
+         *
+         * \note The input data vectors are always double precision to avoid
+         *       losing accuracy when constructing tables.
+         *
+         * \note Since we fill the table for values below range.first, you can achieve
+         *       a smaller table by using a smaller range where the tolerance has to be
+         *       met, and accept that a few function calls below range.first do not
+         *       quite reach the tolerance.
+         *
+         * \warning For efficiency reasons (since this code is used in some inner
+         *       (kernels), we always allocate memory and calculate table indices
+         *       for the complete interval [0,range.second], although the data will
+         *       not be valid outside the definition range to avoid calling the
+         *       function there. This means you should \a not use this class
+         *       to tabulate functions for small ranges very far away from zero,
+         *       since you would both waste a huge amount of memory and incur
+         *       truncation errors when calculating the index.
+         */
+        QuadraticSplineTable(std::initializer_list<NumericalSplineTableInput>    numericalInputList,
+                             const std::pair<real, real>                        &range,
+                             real                                                tolerance = defaultTolerance);
+
+
+        /************************************************************
+         *           Evaluation methods for single functions        *
+         ************************************************************/
+
+        /*! \brief Evaluate both function and derivative, single table function
+         *
+         *  This is a templated method where the template can be either real or SimdReal.
+         *
+         *  \tparam     numFuncInTable  Number of separate functions in table, default is 1
+         *  \tparam     funcIndex       Index of function to evaluate in table, default is 0
+         *  \tparam     T               Type (SimdReal or real) of lookup and result
+         *  \param      r               Points for which to evaluate function and derivative
+         *  \param[out] functionValue   Function value
+         *  \param[out] derivativeValue Function derivative
+         *
+         *  For debug builds we assert that the input values fall in the range
+         *  specified when constructing the table.
+         */
+        template <int numFuncInTable = 1, int funcIndex = 0, typename T>
+        void
+        evaluateFunctionAndDerivative(T     r,
+                                      T *   functionValue,
+                                      T *   derivativeValue) const
+        {
+            rangeCheck(r);
+            GMX_ASSERT(numFuncInTable == numFuncInTable_, "Evaluation method not matching number of functions in table");
+            GMX_ASSERT(funcIndex < numFuncInTable, "Function index not in range of the number of tables");
+
+            T     rTable   = r * T(tableScale_);
+            auto  tabIndex = cvttR2I(rTable); // type is either std::int32_t or SimdInt32
+            T     eps      = rTable - trunc(rTable);
+            T     t0;
+            T     t1;
+            T     t2;
+            T     t3 gmx_unused;
+
+            // Load Derivative, Delta, Function, and Zero values for each table point.
+            // The 4 refers to these four values - not any SIMD width.
+            gatherLoadBySimdIntTranspose<4*numFuncInTable>(ddfzMultiTableData_.data() + 4 * funcIndex, tabIndex, &t0, &t1, &t2, &t3);
+
+            t1               = t0 + eps * t1;
+            *functionValue   = fma( eps * T(halfSpacing_),  t0 + t1, t2);
+            *derivativeValue = t1;
+        }
+
+        /*! \brief Evaluate function value only, single table function
+         *
+         *  This is a templated method where the template can be either real or SimdReal.
+         *
+         *  \tparam     numFuncInTable  Number of separate functions in table, default is 1
+         *  \tparam     funcIndex       Index of function to evaluate in table, default is 0
+         *  \tparam     T               Type (SimdReal or real) of lookup and result
+         *  \param      r               Points for which to evaluate function value
+         *  \param[out] functionValue   Function value
+         *
+         *  For debug builds we assert that the input values fall in the range
+         *  specified when constructing the table.
+         */
+        template <int numFuncInTable = 1, int funcIndex = 0, typename T>
+        void
+        evaluateFunction(T     r,
+                         T *   functionValue) const
+        {
+            T     der gmx_unused;
+
+            evaluateFunctionAndDerivative<numFuncInTable, funcIndex>(r, functionValue, &der);
+        }
+
+        /*! \brief Evaluate function derivative only, single table function
+         *
+         *  This is a templated method where the template can be either real or SimdReal.
+         *
+         *  \tparam     numFuncInTable  Number of separate functions in table, default is 1
+         *  \tparam     funcIndex       Index of function to evaluate in table, default is 0
+         *  \tparam     T               Type (SimdReal or real) of lookup and result
+         *  \param      r               Points for which to evaluate function derivative
+         *  \param[out] derivativeValue Function derivative
+         *
+         *  For debug builds we assert that the input values fall in the range
+         *  specified when constructing the table.
+         */
+        template <int numFuncInTable = 1, int funcIndex = 0, typename T>
+        void
+        evaluateDerivative(T     r,
+                           T *   derivativeValue) const
+        {
+            rangeCheck(r);
+            GMX_ASSERT(numFuncInTable == numFuncInTable_, "Evaluation method not matching number of functions in table");
+            GMX_ASSERT(funcIndex < numFuncInTable, "Function index not in range of the number of tables");
+
+            T     rTable   = r * T(tableScale_);
+            auto  tabIndex = cvttR2I(rTable); // type is either std::int32_t or SimdInt32
+            T     eps      = rTable - trunc(rTable);
+            T     t0;
+            T     t1;
+            T     t2 gmx_unused;
+
+            if (numFuncInTable == 1)
+            {
+                gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex, tabIndex, &t0, &t1); // works for scalar T too
+            }
+            else
+            {
+                // This is not ideal, but we need a version of gatherLoadUBySimdIntTranspose that
+                // only loads a single value from memory to implement it better (will be written)
+                gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex, tabIndex, &t0, &t2);        // works for scalar T too
+                gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex, tabIndex + T(1), &t1, &t2); // works for scalar T too
+            }
+
+            // (1-eps)*t0 + eps*t1
+            *derivativeValue = fma(t1-t0, eps, t0);
+        }
+
+        /************************************************************
+         *             Evaluation methods for two functions         *
+         ************************************************************/
+
+        /*! \brief Evaluate both function and derivative, two table functions
+         *
+         *  This is a templated method where the template can be either real or SimdReal.
+         *
+         *  \tparam     numFuncInTable  Number of separate functions in table, default is 2
+         *  \tparam     funcIndex0       Index of 1st function to evaluate in table, default is 0
+         *  \tparam     funcIndex1       Index of 2nd function to evaluate in table, default is 1
+         *  \tparam     T                Type (SimdReal or real) of lookup and result
+         *  \param      r                Points for which to evaluate function and derivative
+         *  \param[out] functionValue1   Interpolated value for first function
+         *  \param[out] derivativeValue1 Interpolated derivative for first function
+         *  \param[out] functionValue2   Interpolated value for second function
+         *  \param[out] derivativeValue2 Interpolated derivative for second function
+         *
+         *  For debug builds we assert that the input values fall in the range
+         *  specified when constructing the table.
+         */
+        template <int numFuncInTable = 2, int funcIndex0 = 0, int funcIndex1 = 1, typename T>
+        void
+        evaluateFunctionAndDerivative(T     r,
+                                      T *   functionValue1,
+                                      T *   derivativeValue1,
+                                      T *   functionValue2,
+                                      T *   derivativeValue2) const
+        {
+            rangeCheck(r);
+            GMX_ASSERT(numFuncInTable == numFuncInTable_, "Evaluation method not matching number of functions in table");
+            GMX_ASSERT(funcIndex0 < numFuncInTable && funcIndex1 < numFuncInTable, "Function index not in range of the number of tables");
+
+            T     rTable   = r * T(tableScale_);
+            auto  tabIndex = cvttR2I(rTable); // type is either std::int32_t or SimdInt32
+            T     eps      = rTable - trunc(rTable);
+            T     t0;
+            T     t1;
+            T     t2;
+            T     t3 gmx_unused;
+
+            // Load Derivative, Delta, Function, and Zero values for each table point.
+            // The 4 refers to these four values - not any SIMD width.
+            gatherLoadBySimdIntTranspose<4*numFuncInTable>(ddfzMultiTableData_.data() + 4*funcIndex0, tabIndex, &t0, &t1, &t2, &t3);
+            t1                = t0 + eps * t1;
+            *functionValue1   = fma( eps * T(halfSpacing_),  t0 + t1, t2);
+            *derivativeValue1 = t1;
+
+            gatherLoadBySimdIntTranspose<4*numFuncInTable>(ddfzMultiTableData_.data() + 4*funcIndex1, tabIndex, &t0, &t1, &t2, &t3);
+            t1                = t0 + eps * t1;
+            *functionValue2   = fma( eps * T(halfSpacing_),  t0 + t1, t2);
+            *derivativeValue2 = t1;
+        }
+
+        /*! \brief Evaluate function value only, two table functions
+         *
+         *  This is a templated method where the template can be either real or SimdReal.
+         *
+         *  \tparam     numFuncInTable   Number of separate functions in table, default is 2
+         *  \tparam     funcIndex0       Index of 1st function to evaluate in table, default is 0
+         *  \tparam     funcIndex1       Index of 2nd function to evaluate in table, default is 1
+         *  \tparam     T                Type (SimdReal or real) of lookup and result
+         *  \param      r                Points for which to evaluate function value
+         *  \param[out] functionValue1   Interpolated value for first function
+         *  \param[out] functionValue2   Interpolated value for second function
+         *
+         *  For debug builds we assert that the input values fall in the range
+         *  specified when constructing the table.
+         */
+        template <int numFuncInTable = 2, int funcIndex0 = 0, int funcIndex1 = 1, typename T>
+        void
+        evaluateFunction(T     r,
+                         T *   functionValue1,
+                         T *   functionValue2) const
+        {
+            T     der1 gmx_unused;
+            T     der2 gmx_unused;
+
+            evaluateFunctionAndDerivative<numFuncInTable, funcIndex0, funcIndex1>(r, functionValue1, &der1, functionValue2, &der2);
+        }
+
+        /*! \brief Evaluate function derivative only, two table functions
+         *
+         *  This is a templated method where the template can be either real or SimdReal.
+         *
+         *  \tparam     numFuncInTable   Number of separate functions in table, default is 2
+         *  \tparam     funcIndex0       Index of 1st function to evaluate in table, default is 0
+         *  \tparam     funcIndex1       Index of 2nd function to evaluate in table, default is 1
+         *  \tparam     T                Type (SimdReal or real) of lookup and result
+         *  \param      r                Points for which to evaluate function derivative
+         *  \param[out] derivativeValue1 Interpolated derivative for first function
+         *  \param[out] derivativeValue2 Interpolated derivative for second function
+         *
+         *  For debug builds we assert that the input values fall in the range
+         *  specified when constructing the table.
+         */
+        template <int numFuncInTable = 2, int funcIndex0 = 0, int funcIndex1 = 1, typename T>
+        void
+        evaluateDerivative(T     r,
+                           T *   derivativeValue1,
+                           T *   derivativeValue2) const
+        {
+            rangeCheck(r);
+            GMX_ASSERT(numFuncInTable == numFuncInTable_, "Evaluation method not matching number of functions in table");
+            GMX_ASSERT(funcIndex0 < numFuncInTable && funcIndex1 < numFuncInTable, "Function index not in range of the number of tables");
+
+            T     rTable   = r * T(tableScale_);
+            auto  tabIndex = cvttR2I(rTable); // type is either std::int32_t or SimdInt32
+            T     eps      = rTable - trunc(rTable);
+
+            if (numFuncInTable == 2 && funcIndex0 == 0 && funcIndex1 == 1)
+            {
+                T t0A, t0B, t1A, t1B;
+                gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data(), tabIndex, &t0A, &t0B);     // works for scalar T too
+                gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + 2, tabIndex, &t1A, &t1B); // works for scalar T too
+                *derivativeValue1 = fma(t1A-t0A, eps, t0A);
+                *derivativeValue2 = fma(t1B-t0B, eps, t0B);
+            }
+            else
+            {
+                T t0, t1, t2;
+                // This is not ideal, but we need a version of gatherLoadUBySimdIntTranspose that
+                // only loads a single value from memory to implement it better (will be written)
+                gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex0, tabIndex, &t0, &t2);        // works for scalar T too
+                gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex0, tabIndex + T(1), &t1, &t2); // works for scalar T too
+                *derivativeValue1 = fma(t1-t0, eps, t0);
+
+                gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex1, tabIndex, &t0, &t2);        // works for scalar T too
+                gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex1, tabIndex + T(1), &t1, &t2); // works for scalar T too
+                *derivativeValue2 = fma(t1-t0, eps, t0);
+            }
+        }
+
+        /************************************************************
+         *            Evaluation methods for three functions        *
+         ************************************************************/
+
+
+        /*! \brief Evaluate both function and derivative, three table functions
+         *
+         *  This is a templated method where the template can be either real or SimdReal.
+         *
+         *  \tparam     numFuncInTable   Number of separate functions in table, default is 3
+         *  \tparam     funcIndex0       Index of 1st function to evaluate in table, default is 0
+         *  \tparam     funcIndex1       Index of 2nd function to evaluate in table, default is 1
+         *  \tparam     funcIndex2       Index of 3rd function to evaluate in table, default is 2
+         *  \tparam     T                Type (SimdReal or real) of lookup and result
+         *  \param      r                Points for which to evaluate function and derivative
+         *  \param[out] functionValue1   Interpolated value for first function
+         *  \param[out] derivativeValue1 Interpolated derivative for first function
+         *  \param[out] functionValue2   Interpolated value for second function
+         *  \param[out] derivativeValue2 Interpolated derivative for second function
+         *  \param[out] functionValue3   Interpolated value for third function
+         *  \param[out] derivativeValue3 Interpolated derivative for third function
+         *
+         *  For debug builds we assert that the input values fall in the range
+         *  specified when constructing the table.
+         */
+        template <int numFuncInTable = 3, int funcIndex0 = 0, int funcIndex1 = 1, int funcIndex2 = 2, typename T>
+        void
+        evaluateFunctionAndDerivative(T     r,
+                                      T *   functionValue1,
+                                      T *   derivativeValue1,
+                                      T *   functionValue2,
+                                      T *   derivativeValue2,
+                                      T *   functionValue3,
+                                      T *   derivativeValue3) const
+        {
+            rangeCheck(r);
+            GMX_ASSERT(numFuncInTable == numFuncInTable, "Evaluation method not matching number of functions in table");
+            GMX_ASSERT(funcIndex0 < numFuncInTable  && funcIndex1 < numFuncInTable  && funcIndex2 < numFuncInTable,
+                       "Function index not in range of the number of tables");
+
+            T     rTable   = r * T(tableScale_);
+            auto  tabIndex = cvttR2I(rTable); // type is either std::int32_t or SimdInt32
+            T     eps      = rTable - trunc(rTable);
+            T     t0;
+            T     t1;
+            T     t2;
+            T     t3 gmx_unused;
+
+            gatherLoadBySimdIntTranspose<4*numFuncInTable>(ddfzMultiTableData_.data() + 4*funcIndex0, tabIndex, &t0, &t1, &t2, &t3);
+            t1                = t0 + eps * t1;
+            *functionValue1   = fma( eps * T(halfSpacing_),  t0 + t1, t2);
+            *derivativeValue1 = t1;
+
+            gatherLoadBySimdIntTranspose<4*numFuncInTable>(ddfzMultiTableData_.data() + 4*funcIndex1, tabIndex, &t0, &t1, &t2, &t3);
+            t1                = t0 + eps * t1;
+            *functionValue2   = fma( eps * T(halfSpacing_),  t0 + t1, t2);
+            *derivativeValue2 = t1;
+
+            gatherLoadBySimdIntTranspose<4*numFuncInTable>(ddfzMultiTableData_.data() + 4*funcIndex2, tabIndex, &t0, &t1, &t2, &t3);
+            t1                = t0 + eps * t1;
+            *functionValue3   = fma( eps * T(halfSpacing_),  t0 + t1, t2);
+            *derivativeValue3 = t1;
+        }
+
+        /*! \brief Evaluate function value only, three table functions
+         *
+         *  This is a templated method where the template can be either real or SimdReal.
+         *
+         *  \tparam     numFuncInTable   Number of separate functions in table, default is 3
+         *  \tparam     funcIndex0       Index of 1st function to evaluate in table, default is 0
+         *  \tparam     funcIndex1       Index of 2nd function to evaluate in table, default is 1
+         *  \tparam     funcIndex2       Index of 3rd function to evaluate in table, default is 2
+         *  \tparam     T                Type (SimdReal or real) of lookup and result
+         *  \param      r                Points for which to evaluate function value
+         *  \param[out] functionValue1   Interpolated value for first function
+         *  \param[out] functionValue2   Interpolated value for second function
+         *  \param[out] functionValue3   Interpolated value for third function
+         *
+         *  For debug builds we assert that the input values fall in the range
+         *  specified when constructing the table.
+         */
+        template <int numFuncInTable = 3, int funcIndex0 = 0, int funcIndex1 = 1, int funcIndex2 = 2, typename T>
+        void
+        evaluateFunction(T     r,
+                         T *   functionValue1,
+                         T *   functionValue2,
+                         T *   functionValue3) const
+        {
+            T     der1 gmx_unused;
+            T     der2 gmx_unused;
+            T     der3 gmx_unused;
+
+            evaluateFunctionAndDerivative<numFuncInTable, funcIndex0, funcIndex1, funcIndex2>(r, functionValue1, &der1, functionValue2, &der2, functionValue3, &der3);
+        }
+
+        /*! \brief Evaluate function derivative only, three table functions
+         *
+         *  This is a templated method where the template can be either real or SimdReal.
+         *
+         *  \tparam     numFuncInTable   Number of separate functions in table, default is 3
+         *  \tparam     funcIndex0       Index of 1st function to evaluate in table, default is 0
+         *  \tparam     funcIndex1       Index of 2nd function to evaluate in table, default is 1
+         *  \tparam     funcIndex2       Index of 3rd function to evaluate in table, default is 2
+         *  \tparam     T                Type (SimdReal or real) of lookup and result
+         *  \param      r                Points for which to evaluate function derivative
+         *  \param[out] derivativeValue1 Interpolated derivative for first function
+         *  \param[out] derivativeValue2 Interpolated derivative for second function
+         *  \param[out] derivativeValue3 Interpolated derivative for third function
+         *
+         *  For debug builds we assert that the input values fall in the range
+         *  specified when constructing the table.
+         */
+        template <int numFuncInTable = 3, int funcIndex0 = 0, int funcIndex1 = 1, int funcIndex2 = 2, typename T>
+        void
+        evaluateDerivative(T     r,
+                           T *   derivativeValue1,
+                           T *   derivativeValue2,
+                           T *   derivativeValue3) const
+        {
+            rangeCheck(r);
+            GMX_ASSERT(numFuncInTable == numFuncInTable_, "Evaluation method not matching number of functions in table");
+            GMX_ASSERT(funcIndex0 < numFuncInTable  && funcIndex1 < numFuncInTable  && funcIndex2 < numFuncInTable,
+                       "Function index not in range of the number of tables");
+
+            T     rTable   = r * T(tableScale_);
+            auto  tabIndex = cvttR2I(rTable); // type is either std::int32_t or SimdInt32
+            T     eps      = rTable - trunc(rTable);
+
+            if (numFuncInTable == 3 && funcIndex0 == 0 && funcIndex1 == 1 && funcIndex2 == 2)
+            {
+                T t0A, t0B, t0C, t1A, t1B, t1C;
+                gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data(), tabIndex, &t0A, &t0B);
+                gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + 2, tabIndex, &t0C, &t1A);
+                gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + 4, tabIndex, &t1B, &t1C);
+                *derivativeValue1 = fma(t1A-t0A, eps, t0A);
+                *derivativeValue2 = fma(t1B-t0B, eps, t0B);
+                *derivativeValue3 = fma(t1C-t0C, eps, t0C);
+            }
+            else
+            {
+                T t0, t1, t2;
+                // This is not ideal, but we need a version of gatherLoadUBySimdIntTranspose that
+                // only loads a single value from memory to implement it better (will be written)
+                gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex0, tabIndex, &t0, &t2);        // works for scalar T too
+                gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex0, tabIndex + T(1), &t1, &t2); // works for scalar T too
+                *derivativeValue1 = fma(t1-t0, eps, t0);
+
+                gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex1, tabIndex, &t0, &t2);        // works for scalar T too
+                gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex1, tabIndex + T(1), &t1, &t2); // works for scalar T too
+                *derivativeValue2 = fma(t1-t0, eps, t0);
+
+                gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex2, tabIndex, &t0, &t2);        // works for scalar T too
+                gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex2, tabIndex + T(1), &t1, &t2); // works for scalar T too
+                *derivativeValue3 = fma(t1-t0, eps, t0);
+            }
+        }
+
+        /*! \brief Return the table spacing (distance between points)
+         *
+         *  You should never have to use this for normal code, but due to the
+         *  way tables are constructed internally we need this in the unit tests
+         *  to check relative tolerances over each interval.
+         *
+         *  \return table spacing.
+         */
+        real
+        tableSpacing() const { return 1.0 / tableScale_; }
+
+    private:
+
+        std::size_t             numFuncInTable_; //!< Number of separate tabluated functions
+        std::pair<real, real>   range_;          //!< Range for which table evaluation is allowed
+        real                    tableScale_;     //!< Table scale (inverse of spacing between points)
+        real                    halfSpacing_;    //!< 0.5*spacing (used for DDFZ table data)
+
+        //!< Derivative values only, with the third-derivative subtraction described in the class documentation.
+        std::vector<real>      derivativeMultiTableData_;
+
+        /*! \brief Combined derivative, difference to next derivative, value, and zero.
+         *
+         *  For table point i, this vector contains the four values:
+         *  - derivative[i]
+         *  - (derivative[i+1]-derivative[i])
+         *  - value[i]
+         *  - 0.0
+         *
+         *  For the derivative terms we have subtracted the third-derivative term described
+         *  in the main class documentation.
+         *
+         *  This is typically more efficient than the individual tables, in particular
+         *  when using SIMD. The result should be identical outside the class, so this
+         *  is merely an internal implementation optimization. However, to allow
+         *  aligned SIMD loads we need to use an aligned allocator for this container.
+         *  We occasionally abbreviate this data as DDFZ.
+         */
+        std::vector<real, AlignedAllocator<real> >  ddfzMultiTableData_;
+
+        // There should never be any reason to copy the table since it is read-only
+        GMX_DISALLOW_COPY_AND_ASSIGN(QuadraticSplineTable);
+};
+
+
+}      // namespace gmx
+
+#endif // GMX_TABLES_QUADRATICSPLINETABLE_H
diff --git a/src/gromacs/tables/splineutil.cpp b/src/gromacs/tables/splineutil.cpp
new file mode 100644 (file)
index 0000000..1e4452e
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+
+/*! \internal \file
+ * \brief
+ * Implements internal utility functions for spline tables
+ *
+ * \author Erik Lindahl <erik.lindahl@gmail.com>
+ * \ingroup module_tables
+ */
+#include "gmxpre.h"
+
+#include "splineutil.h"
+
+#include <cmath>
+
+#include <algorithm>
+#include <functional>
+#include <utility>
+#include <vector>
+
+#include "gromacs/utility/alignedallocator.h"
+#include "gromacs/utility/arrayref.h"
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/real.h"
+#include "gromacs/utility/stringutil.h"
+
+namespace gmx
+{
+
+namespace internal
+{
+
+void
+throwUnlessDerivativeIsConsistentWithFunction(const std::function<double(double)>  &function,
+                                              const std::function<double(double)>  &derivative,
+                                              const std::pair<real, real>          &range)
+{
+    // Since the numerical derivative will evaluate extra points
+    // we shrink the interval slightly to avoid calling the function with values
+    // outside the range specified.
+    double                     h            = std::cbrt(GMX_DOUBLE_EPS); // ideal spacing
+    std::pair<double, double>  newRange(range.first + h, range.second - h);
+    const int                  points       = 1000;                      // arbitrary
+    double                     dx           = (newRange.second - newRange.first) / points;
+    bool                       isConsistent = true;
+    double                     minFail      = newRange.second;
+    double                     maxFail      = newRange.first;
+
+    for (double x = newRange.first; x <= newRange.second; x += dx)
+    {
+        double analyticalDerivative = derivative(x);
+        double numericalDerivative  = (function(x+h)-function(x-h))/(2*h);
+        double thirdDerivative      = (derivative(x+h)-2.0*derivative(x)+derivative(x-h))/(h*h);
+
+        // We make two types of errors in numerical calculation of the derivative:
+        // - The truncation error: eps * |f| / h
+        // - The rounding error: h * h * |f'''| / 6.0
+        double expectedErr = GMX_DOUBLE_EPS*std::abs(function(x))/h + h*h*std::abs(thirdDerivative)/6.0;
+
+        // To avoid triggering false errors because of compiler optimization or numerical issues
+        // in the function evalulation we allow an extra factor of 10 in the expected error
+        if (std::abs(analyticalDerivative-numericalDerivative) > 10.0*expectedErr)
+        {
+            isConsistent = false;
+            minFail      = std::min(minFail, x);
+            maxFail      = std::max(maxFail, x);
+        }
+    }
+
+    if (!isConsistent)
+    {
+        GMX_THROW(InconsistentInputError(formatString("Derivative inconsistent with analytical function in range [%d,%d]", minFail, maxFail)));
+    }
+}
+
+
+void
+throwUnlessDerivativeIsConsistentWithFunction(ConstArrayRef<double>         function,
+                                              ConstArrayRef<double>         derivative,
+                                              double                        inputSpacing,
+                                              const std::pair<real, real>  &range)
+{
+    std::size_t     firstIndex   = range.first / inputSpacing;
+    std::size_t     lastIndex    = range.second / inputSpacing;
+    bool            isConsistent = true;
+    std::size_t     minFail      = lastIndex;
+    std::size_t     maxFail      = firstIndex;
+
+    // The derivative will access one extra point before/after each point, so reduce interval
+    for (std::size_t i = firstIndex + 1; (i + 1) < lastIndex; i++)
+    {
+        double inputDerivative     = derivative[i];
+        double numericalDerivative = (function[i+1] - function[i-1]) / (2.0 * inputSpacing);
+        double thirdDerivative     = (derivative[i+1] - 2.0*derivative[i] + derivative[i-1])/(inputSpacing * inputSpacing);
+
+        // We make two types of errors in numerical calculation of the derivative:
+        // - The truncation error: eps * |f| / h
+        // - The rounding error: h * h * |f'''| / 6.0
+        double expectedErr = GMX_DOUBLE_EPS*std::abs(function[i])/inputSpacing + inputSpacing*inputSpacing*std::abs(thirdDerivative)/6.0;
+
+        // To avoid triggering false errors because of compiler optimization or numerical issues
+        // in the function evalulation we allow an extra factor of 10 in the expected error
+        if (std::abs(inputDerivative-numericalDerivative) > 10.0*expectedErr)
+        {
+            isConsistent = false;
+            minFail      = std::min(minFail, i);
+            maxFail      = std::max(maxFail, i);
+        }
+    }
+    if (!isConsistent)
+    {
+        GMX_THROW(InconsistentInputError(formatString("Derivative inconsistent with numerical vector for elements %d-%d", minFail+1, maxFail+1)));
+    }
+}
+
+
+/*! \brief Update minQuotient if the ratio of this function value and its second derivative is smaller
+ *
+ * This is a utility function used in the functions to find the smallest quotient
+ * in a range.
+ *
+ * \param[in]    previousPoint Value of function at x-h.
+ * \param[in]    thisPoint     Value of function at x.
+ * \param[in]    nextPoint     Value of function at x+h.
+ * \param[in]    spacing       Value of h.
+ * \param[inout] minQuotient   Current minimum of such quotients, updated if this quotient is smaller.
+ */
+static void
+updateMinQuotientOfFunctionAndSecondDerivative(double     previousPoint,
+                                               double     thisPoint,
+                                               double     nextPoint,
+                                               double     spacing,
+                                               double *   minQuotient)
+{
+    double value             = std::abs( thisPoint );
+    double secondDerivative  = std::abs( (previousPoint - 2.0 * thisPoint + nextPoint) / (spacing * spacing ) );
+
+    // Make sure we do not divide by zero. This limit is arbitrary,
+    // but it doesnt matter since this point will have a very large value,
+    // and the whole routine is searching for the smallest value.
+    secondDerivative = std::max(secondDerivative, static_cast<double>(std::sqrt(GMX_REAL_MIN)));
+
+    *minQuotient = std::min(*minQuotient, value / secondDerivative);
+}
+
+
+real
+findSmallestQuotientOfFunctionAndSecondDerivative(const std::function<double(double)>   &f,
+                                                  const std::pair<real, real>           &range)
+{
+    // Since the numerical second derivative will evaluate extra points
+    // we shrink the interval slightly to avoid calling the function with values
+    // outside the range specified.
+    double                     h           = std::pow( GMX_DOUBLE_EPS, 0.25 );
+    std::pair<double, double>  newRange(range.first + h, range.second - h);
+    const int                  points      = 1000; // arbitrary
+    double                     dx          = (newRange.second - newRange.first) / points;
+    double                     minQuotient = GMX_REAL_MAX;
+
+    for (double x = newRange.first; x <= newRange.second; x += dx)
+    {
+        updateMinQuotientOfFunctionAndSecondDerivative(f(x-h), f(x), f(x+h), h, &minQuotient);
+    }
+    return static_cast<real>(minQuotient);
+}
+
+
+
+
+
+
+real
+findSmallestQuotientOfFunctionAndSecondDerivative(ConstArrayRef<double>         function,
+                                                  double                        inputSpacing,
+                                                  const std::pair<real, real>   &range)
+{
+
+    std::size_t  firstIndex  = range.first  / inputSpacing;
+    std::size_t  lastIndex   = range.second / inputSpacing;
+    double       minQuotient = GMX_REAL_MAX;
+
+    for (std::size_t i = firstIndex + 1; (i + 1) < lastIndex; i++)
+    {
+        updateMinQuotientOfFunctionAndSecondDerivative(function[i-1], function[i], function[i+1], inputSpacing, &minQuotient);
+    }
+    return static_cast<real>(minQuotient);
+}
+
+
+
+/*! \brief Update minQuotient if the ratio of this function value and its third derivative is smaller
+ *
+ * This is a utility function used in the functions to find the smallest quotient
+ * in a range.
+ *
+ * \param[in]    previousPreviousPoint Value of function at x-2h.
+ * \param[in]    previousPoint         Value of function at x-h.
+ * \param[in]    thisPoint             Value of function at x.
+ * \param[in]    nextPoint             Value of function at x+h.
+ * \param[in]    nextNextPoint         Value of function at x+2h.
+ * \param[in]    spacing               Value of h.
+ * \param[inout] minQuotient   Current minimum of such quotients, updated if this quotient is smaller.
+ */
+static void
+updateMinQuotientOfFunctionAndThirdDerivative(double     previousPreviousPoint,
+                                              double     previousPoint,
+                                              double     thisPoint,
+                                              double     nextPoint,
+                                              double     nextNextPoint,
+                                              double     spacing,
+                                              double *   minQuotient)
+{
+    double value            = std::abs( thisPoint );
+    double thirdDerivative  = std::abs((nextNextPoint - 2 * nextPoint + 2 * previousPoint - previousPreviousPoint) / (2 * spacing * spacing * spacing));
+
+    // Make sure we do not divide by zero. This limit is arbitrary,
+    // but it doesnt matter since this point will have a very large value,
+    // and the whole routine is searching for the smallest value.
+    thirdDerivative = std::max(thirdDerivative, static_cast<double>(std::sqrt(GMX_REAL_MIN)));
+
+    *minQuotient = std::min(*minQuotient, value / thirdDerivative);
+}
+
+
+real
+findSmallestQuotientOfFunctionAndThirdDerivative(const std::function<double(double)>  &f,
+                                                 const std::pair<real, real>           &range)
+{
+    // Since the numerical second derivative will evaluate extra points
+    // we shrink the interval slightly to avoid calling the function with values
+    // outside the range specified.
+    double                     h           = std::pow( GMX_DOUBLE_EPS, 0.2 ); // optimal spacing for 3rd derivative
+    std::pair<double, double>  newRange(range.first + 2*h, range.second - 2*h);
+    const int                  points      = 1000;                            // arbitrary
+    double                     dx          = (newRange.second - newRange.first) / points;
+    double                     minQuotient = GMX_REAL_MAX;
+
+    for (double x = newRange.first; x <= newRange.second; x += dx)
+    {
+        updateMinQuotientOfFunctionAndThirdDerivative(f(x-2*h), f(x-h), f(x), f(x+h), f(x+2*h), h, &minQuotient);
+    }
+    return static_cast<real>(minQuotient);
+}
+
+
+real
+findSmallestQuotientOfFunctionAndThirdDerivative(ConstArrayRef<double>         function,
+                                                 double                        inputSpacing,
+                                                 const std::pair<real, real>   &range)
+{
+
+    std::size_t  firstIndex  = range.first  / inputSpacing;
+    std::size_t  lastIndex   = range.second / inputSpacing;
+    double       minQuotient = GMX_REAL_MAX;
+
+    for (std::size_t i = firstIndex + 2; (i + 2) < lastIndex; i++)
+    {
+        updateMinQuotientOfFunctionAndThirdDerivative(function[i-2], function[i-1], function[i], function[i+1], function[i+2], inputSpacing, &minQuotient);
+    }
+    return static_cast<real>(minQuotient);
+}
+
+
+
+std::vector<double>
+vectorSecondDerivative(ConstArrayRef<double> f, double spacing)
+{
+    if (f.size() < 5)
+    {
+        GMX_THROW(APIError("Too few points in vector for 5-point differentiation"));
+    }
+
+    std::vector<double> d(f.size());
+    std::size_t         i;
+
+    // 5-point formula evaluated for points 0,1
+    i    = 0;
+    d[i] = (11 * f[i+4] - 56 * f[i+3] + 114 * f[i+2] - 104 * f[i+1] + 35 * f[i]) / ( 12 * spacing * spacing);
+    i    = 1;
+    d[i] = (-f[i+3] + 4 * f[i+2] + 6 * f[i+1] - 20 * f[i] + 11 * f[i-1]) / ( 12 * spacing * spacing);
+
+    for (std::size_t i = 2; i < d.size() - 2; i++)
+    {
+        // 5-point formula evaluated for central point (2)
+        d[i] = (-f[i+2] + 16 * f[i+1] - 30 * f[i] + 16 * f[i-1] - f[i-2]) / (12 * spacing * spacing);
+    }
+
+    // 5-point formula evaluated for points 3,4
+    i    = d.size() - 2;
+    d[i] = (11 * f[i+1] - 20 * f[i] + 6 * f[i-1] + 4 * f[i-2] - f[i-3]) / ( 12 * spacing * spacing);
+    i    = d.size() - 1;
+    d[i] = (35 * f[i] - 104 * f[i-1] + 114 * f[i-2] - 56 * f[i-3] + 11 * f[i-4]) / ( 12 * spacing * spacing);
+
+    return d;
+}
+
+
+
+}  // namespace internal
+
+}  // namespace gmx
diff --git a/src/gromacs/tables/splineutil.h b/src/gromacs/tables/splineutil.h
new file mode 100644 (file)
index 0000000..bbf8cdd
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+
+/*! \internal \file
+ * \brief
+ * Declares internal utility functions for spline tables
+ *
+ * \author Erik Lindahl <erik.lindahl@gmail.com>
+ * \ingroup module_tables
+ */
+#ifndef GMX_TABLES_SPLINEUTIL_H
+#define GMX_TABLES_SPLINEUTIL_H
+
+#include <functional>
+#include <utility>
+#include <vector>
+
+#include "gromacs/utility/alignedallocator.h"
+#include "gromacs/utility/arrayref.h"
+#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/real.h"
+
+namespace gmx
+{
+
+namespace internal
+{
+
+/*! \brief Ensure analytical derivative is the derivative of analytical function.
+ *
+ *  This routine evaluates the numerical derivative of the function for
+ *  a few (1000) points in the interval and checks that the relative difference
+ *  between numerical and analytical derivative is within the expected error
+ *  for the numerical derivative approximation we use.
+ *
+ *  The main point of this routine is to make sure the user has not made a
+ *  mistake or sign error when defining the functions.
+ *
+ *  \param function   Analytical function to differentiate
+ *  \param derivative Analytical derivative to compare with
+ *  \param range      Range to test
+ *
+ *  \throws If the provided derivative does not seem to match the function.
+ *
+ *  \note The function/derivative are always double-valued to avoid accuracy loss.
+ */
+void
+throwUnlessDerivativeIsConsistentWithFunction(const std::function<double(double)>  &function,
+                                              const std::function<double(double)>  &derivative,
+                                              const std::pair<real, real>          &range);
+
+/*! \brief Ensure vector of derivative values is the derivative of function vector.
+ *
+ *  This routine differentiates a vector of numerical values and checks
+ *  that the relative difference to a provided vector of numerical derivatives
+ *  is smaller than the expected error from the numerical differentiation.
+ *
+ *  The main point of this routine is to make sure the user has not made a
+ *  mistake or sign error when defining the functions.
+ *
+ *  To avoid problems if the vectors change from zero to finite values at the
+ *  start/end of the interval, we only check inside the range requested.
+ *
+ *  \param function     Numerical function value vector to differentiate
+ *  \param derivative   Numerical derivative vector to compare with
+ *  \param inputSpacing Distance between input points
+ *  \param range        Range to test
+ *
+ *  \throws If the provided derivative does not seem to match the function.
+ *
+ *  \note The function/derivative vectors and spacing are always double-valued
+ *        to avoid accuracy loss.
+ */
+void
+throwUnlessDerivativeIsConsistentWithFunction(ConstArrayRef<double>         function,
+                                              ConstArrayRef<double>         derivative,
+                                              double                        inputSpacing,
+                                              const std::pair<real, real>  &range);
+
+
+
+
+/*! \brief Find smallest quotient between analytical function and its 2nd derivative
+ *
+ *  Used to calculate spacing for quadratic spline tables. This function divides the
+ *  function value by the second derivative (or a very small number when that is zero),
+ *  and returns the smallest such quotient found in the range.
+ *
+ *  Our quadratic tables corresponds to linear interpolation of the derivative,
+ *  which means the derivative will typically have larger error than the value
+ *  when interpolating. The spacing required to reach a particular relative
+ *  tolerance in the derivative depends on the quotient between the first
+ *  derivative and the third derivative of the function itself.
+ *
+ *  You should call this routine with the analytical derivative as the "function"
+ *  parameter, and the quotient between "function and second derivative" will
+ *  then correspond to the quotient bewteen the derivative and the third derivative
+ *  of the actual function we want to tabulate.
+ *
+ *  Since all functions that can be tabulated efficiently are reasonably smooth,
+ *  we simply check 1,000 points in the interval rather than bother about
+ *  implementing any complicated global optimization scheme.
+ *
+ *  \param f          Analytical function
+ *  \param range      Interval
+ *
+ *  \return Smallest quotient found in range.
+ *
+ *  \note The function is always double-valued to avoid accuracy loss.
+ */
+real
+findSmallestQuotientOfFunctionAndSecondDerivative(const std::function<double(double)>  &f,
+                                                  const std::pair<real, real>          &range);
+
+
+
+
+
+/*! \brief Find smallest quotient between vector of values and its 2nd derivative
+ *
+ *  Used to calculate spacing for quadratic spline tables. This function divides the
+ *  function value by the second derivative (or a very small number when that is zero),
+ *  and returns the smallest such quotient found in the range.
+ *
+ *  Our quadratic tables corresponds to linear interpolation of the derivative,
+ *  which means the derivative will typically have larger error than the value
+ *  when interpolating. The spacing required to reach a particular relative
+ *  tolerance in the derivative depends on the quotient between the first
+ *  derivative and the third derivative of the function itself.
+ *
+ *  You should call this routine with the analytical derivative as the "function"
+ *  parameter, and the quotient between "function and second derivative" will
+ *  then correspond to the quotient bewteen the derivative and the third derivative
+ *  of the actual function we want to tabulate.
+ *
+ *  \param function     Vector with function values
+ *  \param inputSpacing Spacing between function values
+ *  \param range        Interval to check
+ *
+ *  \return Smallest quotient found in range.
+ *
+ *  \note The function vector and input spacing are always double-valued to
+ *        avoid accuracy loss.
+ */
+real
+findSmallestQuotientOfFunctionAndSecondDerivative(ConstArrayRef<double>         function,
+                                                  double                        inputSpacing,
+                                                  const std::pair<real, real>  &range);
+
+
+
+
+
+/*! \brief Find smallest quotient between analytical function and its 3rd derivative
+ *
+ *  Used to calculate table spacing. This function divides the function value
+ *  by the second derivative (or a very small number when that is zero), and
+ *  returns the smallest such quotient found in the range.
+ *
+ *  Our quadratic tables corresponds to linear interpolation of the derivative,
+ *  which means the derivative will typically have larger error than the value
+ *  when interpolating. The spacing required to reach a particular relative
+ *  tolerance in the derivative depends on the quotient between the first
+ *  derivative and the third derivative of the function itself.
+ *
+ *  You should call this routine with the analytical derivative as the "function"
+ *  parameter, and the quotient between "function and second derivative" will
+ *  then correspond to the quotient bewteen the derivative and the third derivative
+ *  of the actual function we want to tabulate.
+ *
+ *  Since all functions that can be tabulated efficiently are reasonably smooth,
+ *  we simply check 1,000 points in the interval rather than bother about
+ *  implementing any complicated global optimization scheme.
+ *
+ *  \param f          Analytical function
+ *  \param range      Interval
+ *
+ *  \return Smallest quotient found in range.
+ *
+ *  \note The function is always double-valued to avoid accuracy loss.
+ */
+real
+findSmallestQuotientOfFunctionAndThirdDerivative(const std::function<double(double)>  &f,
+                                                 const std::pair<real, real>          &range);
+
+
+
+
+/*! \brief Find smallest quotient between function and 2nd derivative (vectors)
+ *
+ *  Used to calculate table spacing. This function divides the function value
+ *  by the second derivative (or a very small number when that is zero), and
+ *  returns the smallest such quotient found in the range.
+ *
+ *  Our quadratic tables corresponds to linear interpolation of the derivative,
+ *  which means the derivative will typically have larger error than the value
+ *  when interpolating. The spacing required to reach a particular relative
+ *  tolerance in the derivative depends on the quotient between the first
+ *  derivative and the third derivative of the function itself.
+ *
+ *  You should call this routine with the analytical derivative as the "function"
+ *  parameter, and the quotient between "function and second derivative" will
+ *  then correspond to the quotient bewteen the derivative and the third derivative
+ *  of the actual function we want to tabulate.
+ *
+ *  \param function     Vector with function values
+ *  \param inputSpacing Spacing between function values
+ *  \param range        Interval to check
+ *
+ *  \return Smallest quotient found in range.
+ *
+ *  \note The function vector and input spacing are always double-valued to
+ *        avoid accuracy loss.
+ */
+real
+findSmallestQuotientOfFunctionAndThirdDerivative(ConstArrayRef<double>         function,
+                                                 double                        inputSpacing,
+                                                 const std::pair<real, real>  &range);
+
+
+/*! \brief Calculate second derivative of vector and return vector of same length
+ *
+ *  5-point approximations are used, with endpoints using non-center interpolation.
+ *
+ *  \param f       Vector (function) for which to calculate second derivative
+ *  \param spacing Spacing of input data.
+ *
+ *  \throws If the input vector has fewer than five data points.
+ *
+ * \note This function always uses double precision arguments since it is meant
+ *       to be used on raw user input data for tables, where we want to avoid
+ *       accuracy loss (since differentiation can be numerically fragile).
+ */
+std::vector<double>
+vectorSecondDerivative(ConstArrayRef<double>        f,
+                       double                       spacing);
+
+
+/*! \brief Copy (temporary) table data into aligned multiplexed vector
+ *
+ *  This routine takes the temporary data generated for a single table
+ *  and writes multiplexed output into a multiple-table-data vector.
+ *  If the output vector is empty we will resize it to fit the data, and
+ *  otherwise we assert the size is correct to add out input data.
+ *
+ *  \tparam T     Type of container for input data
+ *  \tparam U     Type of container for output data
+ *
+ *  \param[in]    inputData               Input data for single table
+ *  \param[inout] multiplexedOutputData   Multiplexed output vector, many tables.
+ *  \param[in]    valuesPerTablePoint     Number of real values for each table point,
+ *                                        for instance 4 in DDFZ tables.
+ *  \param[in]    numTables               Number of tables mixed into multiplexed output
+ *  \param[in]    thisTableIndex          Index of this table in multiplexed output
+ *
+ *  \note The output container type can be different from the input since the latter
+ *        sometimes uses an aligned allocator so the data can be loaded efficiently
+ *        in the GROMACS nonbonded kernels.
+ */
+template<class T, class U>
+void
+fillMultiplexedTableData(const T           inputData,
+                         U *               multiplexedOutputData,
+                         std::size_t       valuesPerTablePoint,
+                         std::size_t       numTables,
+                         std::size_t       thisTableIndex)
+{
+    if (multiplexedOutputData->size() == 0)
+    {
+        multiplexedOutputData->resize( inputData.size() * numTables );
+    }
+    else
+    {
+        GMX_ASSERT(inputData.size() * numTables == multiplexedOutputData->size(),
+                   "Size mismatch when multiplexing table data");
+    }
+
+    GMX_ASSERT(inputData.size() % valuesPerTablePoint == 0,
+               "Input table size must be a multiple of valuesPerTablePoint");
+
+    std::size_t points = inputData.size() / valuesPerTablePoint;
+
+    for (std::size_t i = 0; i < points; i++)
+    {
+        std::size_t inputOffset  = valuesPerTablePoint * i;
+        std::size_t outputOffset = valuesPerTablePoint * ( numTables * i + thisTableIndex );
+
+        for (std::size_t j = 0; j < valuesPerTablePoint; j++)
+        {
+            (*multiplexedOutputData)[outputOffset + j] = inputData[inputOffset + j];
+        }
+    }
+}
+
+
+}      // namespace internal
+
+}      // namespace gmx
+
+#endif // GMX_TABLES_SPLINEUTIL_H
diff --git a/src/gromacs/tables/tableinput.h b/src/gromacs/tables/tableinput.h
new file mode 100644 (file)
index 0000000..08b66c2
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+
+/*! \libinternal \file
+ * \brief
+ * Declares structures for analytical or numerical input data to construct tables
+ *
+ * \inlibraryapi
+ * \author Erik Lindahl <erik.lindahl@gmail.com>
+ * \ingroup module_tables
+ */
+
+#ifndef GMX_TABLES_TABLEINPUT_H
+#define GMX_TABLES_TABLEINPUT_H
+
+#include <functional>
+#include <vector>
+
+#include "gromacs/utility/arrayref.h"
+
+namespace gmx
+{
+
+/*! \libinternal \brief Specification for analytical table function (name, function, derivative)
+ */
+struct
+AnalyticalSplineTableInput
+{
+    const std::string                    &desc;        //!< \libinternal Brief description of function
+    std::function<double(double)>         function;    //!< \libinternal Analytical form of function
+    std::function<double(double)>         derivative;  //!< \libinternal Analytical derivative
+};
+
+/*! \libinternal \brief Specification for vector table function (name, function, derivative, spacing)
+ */
+struct
+NumericalSplineTableInput
+{
+    const std::string                    &desc;        //!< \libinternal Brief description of function
+    ConstArrayRef<double>                 function;    //!< \libinternal Vector with function values
+    ConstArrayRef<double>                 derivative;  //!< \libinternal Vector with derivative values
+    double                                spacing;     //!< \libinternal Distance between data points
+};
+
+
+} // namespace gmx
+
+
+#endif // GMX_TABLES_TABLEINPUT_H
diff --git a/src/gromacs/tables/tests/CMakeLists.txt b/src/gromacs/tables/tests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c1cd341
--- /dev/null
@@ -0,0 +1,37 @@
+#
+# This file is part of the GROMACS molecular simulation package.
+#
+# Copyright (c) 2016, by the GROMACS development team, led by
+# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+# and including many others, as listed in the AUTHORS file in the
+# top-level source directory and at http://www.gromacs.org.
+#
+# GROMACS is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1
+# of the License, or (at your option) any later version.
+#
+# GROMACS is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with GROMACS; if not, see
+# http://www.gnu.org/licenses, or write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+#
+# If you want to redistribute modifications to GROMACS, please
+# consider that scientific software is very special. Version
+# control is crucial - bugs must be traceable. We will be happy to
+# consider code for inclusion in the official distribution, but
+# derived work must not be called official GROMACS. Details are found
+# in the README & COPYING files - if they are missing, get the
+# official version at http://www.gromacs.org.
+#
+# To help us fund GROMACS development, we humbly ask that you cite
+# the research papers on the package. Check out http://www.gromacs.org.
+
+gmx_add_unit_test(TableUnitTests table-test
+                  splinetable.cpp
+                  )
diff --git a/src/gromacs/tables/tests/splinetable.cpp b/src/gromacs/tables/tests/splinetable.cpp
new file mode 100644 (file)
index 0000000..44aaf2b
--- /dev/null
@@ -0,0 +1,746 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2015,2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Tests for simple math functions.eval
+ *
+ * \author Erik Lindahl <erik.lindahl@gmail.com>
+ * \ingroup module_tables
+ */
+#include "gmxpre.h"
+
+#include <cmath>
+
+#include <algorithm>
+#include <functional>
+#include <utility>
+
+#include <gtest/gtest.h>
+
+#include "gromacs/math/utilities.h"
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/ioptionscontainer.h"
+#include "gromacs/simd/simd.h"
+#include "gromacs/tables/cubicsplinetable.h"
+#include "gromacs/tables/quadraticsplinetable.h"
+
+#include "testutils/testasserts.h"
+#include "testutils/testoptions.h"
+
+
+namespace gmx
+{
+
+namespace test
+{
+
+namespace
+{
+
+class SplineTableTestBase : public ::testing::Test
+{
+    public:
+        static int  s_testPoints_; //!< Number of points to use. Public so we can set it as option
+};
+
+int
+SplineTableTestBase::s_testPoints_ = 100;
+
+/*! \cond */
+/*! \brief Command-line option to adjust the number of points used to test SIMD math functions. */
+GMX_TEST_OPTIONS(SplineTableTestOptions, options)
+{
+    options->addOption(::gmx::IntegerOption("npoints")
+                           .store(&SplineTableTestBase::s_testPoints_)
+                           .description("Number of points to test for spline table functions"));
+}
+/*! \endcond */
+
+
+
+
+/*! \brief Test fixture for table comparision with analytical/numerical functions */
+template <typename T>
+class SplineTableTest : public SplineTableTestBase
+{
+    public:
+        SplineTableTest() : tolerance_(T::defaultTolerance) {}
+
+        /*! \brief Set a new tolerance to be used in table function comparison
+         *
+         *  \param tol New tolerance to use
+         */
+        void
+        setTolerance(real tol) { tolerance_ = tol; }
+
+        //! \cond internal
+        /*! \internal \brief
+         * Assertion predicate formatter for comparing table with function/derivative
+         */
+        template<int numFuncInTable = 1, int funcIndex = 0>
+        void
+        testSplineTableAgainstFunctions(const std::string                    &desc,
+                                        const std::function<double(double)>  &refFunc,
+                                        const std::function<double(double)>  &refDer,
+                                        const T                              &table,
+                                        const std::pair<real, real>          &testRange);
+        //! \endcond
+
+    private:
+        real        tolerance_;    //!< Tolerance to use
+};
+
+template <class T>
+template<int numFuncInTable, int funcIndex>
+void
+SplineTableTest<T>::testSplineTableAgainstFunctions(const std::string                    &desc,
+                                                    const std::function<double(double)>  &refFunc,
+                                                    const std::function<double(double)>  &refDer,
+                                                    const T                              &table,
+                                                    const std::pair<real, real>          &testRange)
+{
+    real                   dx = (testRange.second - testRange.first) / s_testPoints_;
+
+    FloatingPointTolerance funcTolerance(relativeToleranceAsFloatingPoint(0.0, tolerance_));
+
+    for (real x = testRange.first; x < testRange.second; x += dx)
+    {
+        real h                = std::sqrt(GMX_REAL_EPS);
+        real secondDerivative = (refDer(x+h)-refDer(x))/h;
+
+        real testFuncValue;
+        real testDerValue;
+
+        table.template evaluateFunctionAndDerivative<numFuncInTable, funcIndex>(x, &testFuncValue, &testDerValue);
+
+        // Check that we get the same values from function/derivative-only methods
+        real tmpFunc, tmpDer;
+
+        table.template evaluateFunction<numFuncInTable, funcIndex>(x, &tmpFunc);
+
+        table.template evaluateDerivative<numFuncInTable, funcIndex>(x, &tmpDer);
+
+        if (testFuncValue != tmpFunc)
+        {
+            ADD_FAILURE()
+            << "Interpolation inconsistency for table " << desc << std::endl
+            << numFuncInTable << " function(s) in table, testing index " << funcIndex << std::endl
+            << "First failure at x = " << x << std::endl
+            << "Function value when evaluating function & derivative: " << testFuncValue << std::endl
+            << "Function value when evaluating only function:         " << tmpFunc << std::endl;
+            return;
+        }
+        if (testDerValue != tmpDer)
+        {
+            ADD_FAILURE()
+            << "Interpolation inconsistency for table " << desc << std::endl
+            << numFuncInTable << " function(s) in table, testing index " << funcIndex << std::endl
+            << "First failure at x = " << x << std::endl
+            << "Derivative value when evaluating function & derivative: " << testDerValue << std::endl
+            << "Derivative value when evaluating only derivative:       " << tmpDer << std::endl;
+            return;
+        }
+
+        // There are two sources of errors that we need to account for when checking the values,
+        // and we only fail the test if both of these tolerances are violated:
+        //
+        // 1) First, we have the normal relative error of the test vs. reference value. For this
+        //    we use the normal testutils relative tolerance checking.
+        //    However, there is an additional source of error: When we calculate the forces we
+        //    use average higher derivatives over the interval to improve accuracy, but this
+        //    also means we won't reproduce values at table points exactly. This is usually not
+        //    an issue since the tolerances we have are much larger, but when the reference derivative
+        //    value is exactly zero the relative error will be infinite. To account for this, we
+        //    extract the spacing from the table and evaluate the reference derivative at a point
+        //    this much larger too, and use the largest of the two values as the reference
+        //    magnitude for the derivative when setting the relative tolerance.
+        //    Note that according to the table function definitions, we should be allowed to evaluate
+        //    it one table point beyond the range (this is done already for construction).
+        //
+        // 2) Second, due to the loss-of-accuracy when calculating the index through rtable
+        //    there is an internal absolute tolerance that we can calculate.
+        //    The source of this error is the subtraction eps=rtab-[rtab], which leaves an
+        //    error proportional to eps_machine*rtab=eps_machine*x*tableScale.
+        //    To lowest order, the term in the function and derivative values (respectively) that
+        //    are proportional to eps will be the next-higher derivative multiplied by the spacing.
+        //    This means the truncation error in the value is derivative*x*eps_machine, and in the
+        //    derivative the error is 2nd_derivative*x*eps_machine.
+
+        real refFuncValue     = refFunc(x);
+        real refDerValue      = refDer(x);
+        real nextRefDerValue  = refDer(x + table.tableSpacing());
+
+        real derMagnitude     = std::max( std::abs(refDerValue), std::abs(nextRefDerValue));
+
+        // Since the reference magnitude will change over each interval we need to re-evaluate
+        // the derivative tolerance inside the loop.
+        FloatingPointTolerance  derTolerance(relativeToleranceAsFloatingPoint(derMagnitude, tolerance_));
+
+        FloatingPointDifference funcDiff(refFuncValue, testFuncValue);
+        FloatingPointDifference derDiff(refDerValue, testDerValue);
+
+        real                    allowedAbsFuncErr = std::abs(refDerValue)      * x * GMX_REAL_EPS;
+        real                    allowedAbsDerErr  = std::abs(secondDerivative) * x * GMX_REAL_EPS;
+
+        if ((!funcTolerance.isWithin(funcDiff) && funcDiff.asAbsolute() > allowedAbsFuncErr) ||
+            (!derTolerance.isWithin(derDiff)  &&  derDiff.asAbsolute() > allowedAbsDerErr))
+        {
+            ADD_FAILURE()
+            << "Failing comparison with function for table " << desc << std::endl
+            << numFuncInTable << " function(s) in table, testing index " << funcIndex << std::endl
+            << "Test range is ( " << testRange.first << " , " << testRange.second << " ) " << std::endl
+            << "Tolerance             = " << tolerance_ << std::endl
+            << "First failure at    x = " << x << std::endl
+            << "Reference function    = " << refFuncValue << std::endl
+            << "Test table function   = " << testFuncValue << std::endl
+            << "Reference derivative  = " << refDerValue << std::endl
+            << "Test table derivative = " << testDerValue << std::endl;
+            return;
+        }
+    }
+}
+
+
+/*! \brief Function similar to coulomb electrostatics
+ *
+ *  \param r argument
+ *  \return r^-1
+ */
+double
+coulombFunction(double r)
+{
+    return 1.0/r;
+}
+
+/*! \brief Derivative (not force) of coulomb electrostatics
+ *
+ *  \param r argument
+ *  \return -r^-2
+ */
+double
+coulombDerivative(double r)
+{
+    return -1.0/(r*r);
+}
+
+/*! \brief Function similar to power-6 Lennard-Jones dispersion
+ *
+ *  \param r argument
+ *  \return r^-6
+ */
+double
+lj6Function(double r)
+{
+    return std::pow(r, -6.0);
+}
+
+/*! \brief Derivative (not force) of the power-6 Lennard-Jones dispersion
+ *
+ *  \param r argument
+ *  \return -6.0*r^-7
+ */
+double
+lj6Derivative(double r)
+{
+    return -6.0*std::pow(r, -7.0);
+}
+
+/*! \brief Function similar to power-12 Lennard-Jones repulsion
+ *
+ *  \param r argument
+ *  \return r^-12
+ */
+double
+lj12Function(double r)
+{
+    return std::pow(r, -12.0);
+}
+
+/*! \brief Derivative (not force) of the power-12 Lennard-Jones repulsion
+ *
+ *  \param r argument
+ *  \return -12.0*r^-13
+ */
+double
+lj12Derivative(double r)
+{
+    return -12.0*std::pow(r, -13.0);
+}
+
+/*! \brief The sinc function, sin(r)/r
+ *
+ *  \param r argument
+ *  \return sin(r)/r
+ */
+double
+sincFunction(double r)
+{
+    return std::sin(r)/r;
+}
+
+/*! \brief Derivative of the sinc function
+ *
+ *  \param r argument
+ *  \return derivative of sinc, (r*cos(r)-sin(r))/r^2
+ */
+double
+sincDerivative(double r)
+{
+    return (r*std::cos(r)-std::sin(r))/(r*r);
+}
+
+/*! \brief Function for the direct-space PME correction to 1/r
+ *
+ *  \param r argument
+ *  \return PME correction function, erf(r)/r
+ */
+double
+pmeCorrFunction(double r)
+{
+    if (r == 0)
+    {
+        return 2.0/std::sqrt(M_PI);
+    }
+    else
+    {
+        return std::erf(r)/r;
+    }
+}
+
+/*! \brief Derivative of the direct-space PME correction to 1/r
+ *
+ *  \param r argument
+ *  \return Derivative of the PME correction function.
+ */
+double
+pmeCorrDerivative(double r)
+{
+    if (r == 0)
+    {
+        return 0;
+    }
+    else
+    {
+        return (2.0*std::exp(-r*r)/std::sqrt(3.14159265358979323846)*r-erf(r))/(r*r);
+    }
+}
+
+/*! \brief Typed-test list. We test QuadraticSplineTable and CubicSplineTable
+ */
+typedef ::testing::Types<QuadraticSplineTable, CubicSplineTable> SplineTableTypes;
+TYPED_TEST_CASE(SplineTableTest, SplineTableTypes);
+
+
+TYPED_TEST(SplineTableTest, HandlesIncorrectInput)
+{
+    // negative range
+    EXPECT_THROW_GMX(TypeParam( {{"LJ12", lj12Function, lj12Derivative}}, {-1.0, 0.0}), gmx::InvalidInputError);
+
+    // Too small range
+    EXPECT_THROW_GMX(TypeParam( {{"LJ12", lj12Function, lj12Derivative}}, {1.0, 1.00001}), gmx::InvalidInputError);
+
+    // bad tolerance
+    EXPECT_THROW_GMX(TypeParam( {{"LJ12", lj12Function, lj12Derivative}}, {1.0, 2.0}, 1e-20), gmx::ToleranceError);
+
+    // Range is so close to 0.0 that table would require >1e6 points
+    EXPECT_THROW_GMX(TypeParam( {{"LJ12", lj12Function, lj12Derivative}}, {1e-4, 2.0}), gmx::ToleranceError);
+
+    // mismatching function/derivative
+    EXPECT_THROW_GMX(TypeParam( { {"BadLJ12", lj12Derivative, lj12Function}}, {1.0, 2.0}), gmx::InconsistentInputError);
+}
+
+
+#ifndef NDEBUG
+TYPED_TEST(SplineTableTest, CatchesOutOfRangeValues)
+{
+    TypeParam      table( {{"LJ12", lj12Function, lj12Derivative}}, {0.2, 1.0});
+    real           x, func, der;
+
+    x = -GMX_REAL_EPS;
+    EXPECT_THROW_GMX(table.evaluateFunctionAndDerivative(x, &func, &der), gmx::RangeError);
+
+    x = 1.0;
+    EXPECT_THROW_GMX(table.evaluateFunctionAndDerivative(x, &func, &der), gmx::RangeError);
+}
+#endif
+
+
+TYPED_TEST(SplineTableTest, Sinc)
+{
+    std::pair<real, real>  range(0.1, 10);
+
+    TypeParam              sincTable( {{"Sinc", sincFunction, sincDerivative}}, range);
+
+    TestFixture::testSplineTableAgainstFunctions("Sinc", sincFunction, sincDerivative, sincTable, range);
+}
+
+
+TYPED_TEST(SplineTableTest, LJ12)
+{
+    std::pair<real, real>  range(0.2, 2.0);
+
+    TypeParam              lj12Table( {{"LJ12", lj12Function, lj12Derivative}}, range);
+
+    TestFixture::testSplineTableAgainstFunctions("LJ12", lj12Function, lj12Derivative, lj12Table, range);
+}
+
+
+TYPED_TEST(SplineTableTest, PmeCorrection)
+{
+    std::pair<real, real>  range(0.0, 4.0);
+    real                   tolerance = 1e-5;
+
+    TypeParam              pmeCorrTable( {{"PMECorr", pmeCorrFunction, pmeCorrDerivative}}, range, tolerance);
+
+    TestFixture::setTolerance(tolerance);
+    TestFixture::testSplineTableAgainstFunctions("PMECorr", pmeCorrFunction, pmeCorrDerivative, pmeCorrTable, range);
+}
+
+
+
+TYPED_TEST(SplineTableTest, HandlesIncorrectNumericalInput)
+{
+    // Lengths do not match
+    std::vector<double>   functionValues(10);
+    std::vector<double>   derivativeValues(20);
+    EXPECT_THROW_GMX(TypeParam( {{"EmptyVectors", functionValues, derivativeValues, 0.001}},
+                                {1.0, 2.0}), gmx::InconsistentInputError);
+
+    // Upper range is 2.0, spacing 0.1. This requires at least 21 points. Make sure we get an error for 20.
+    functionValues.resize(20);
+    derivativeValues.resize(20);
+    EXPECT_THROW_GMX(TypeParam( {{"EmptyVectors", functionValues, derivativeValues, 0.1}},
+                                {1.0, 2.0}), gmx::InconsistentInputError);
+
+    // Create some test data
+    functionValues.clear();
+    derivativeValues.clear();
+
+    std::vector<double>   badDerivativeValues;
+    double                spacing = 1e-3;
+
+    for (std::size_t i = 0; i < 1001; i++)
+    {
+        double x    = i * spacing;
+        double func = (x >= 0.1) ? lj12Function(x)   : 0.0;
+        double der  = (x >= 0.1) ? lj12Derivative(x) : 0.0;
+
+        functionValues.push_back(func);
+        derivativeValues.push_back(der);
+        badDerivativeValues.push_back(-der);
+    }
+
+    // Derivatives not consistent with function
+    EXPECT_THROW_GMX(TypeParam( {{"NumericalBadLJ12", functionValues, badDerivativeValues, spacing}},
+                                {0.2, 1.0}), gmx::InconsistentInputError);
+
+    // Spacing 1e-3 is not sufficient for r^-12 in range [0.1,1.0]
+    // Make sure we get a tolerance error
+    EXPECT_THROW_GMX(TypeParam( {{"NumericalLJ12", functionValues, derivativeValues, spacing}},
+                                {0.2, 1.0}), gmx::ToleranceError);
+}
+
+
+TYPED_TEST(SplineTableTest, NumericalInputPmeCorr)
+{
+    std::pair<real, real>  range(0.0, 4.0);
+    std::vector<double>    functionValues;
+    std::vector<double>    derivativeValues;
+
+    double                 inputSpacing = 1e-3;
+    real                   tolerance    = 1e-5;
+
+    // We only need data up to the argument 4.0, but add 1% margin
+    for (std::size_t i = 0; i < range.second*1.01/inputSpacing; i++)
+    {
+        double x    = i * inputSpacing;
+
+        functionValues.push_back(pmeCorrFunction(x));
+        derivativeValues.push_back(pmeCorrDerivative(x));
+    }
+
+    TypeParam  pmeCorrTable( {{"NumericalPMECorr", functionValues, derivativeValues, inputSpacing}},
+                             range, tolerance);
+
+    TestFixture::setTolerance(tolerance);
+    TestFixture::testSplineTableAgainstFunctions("NumericalPMECorr", pmeCorrFunction, pmeCorrDerivative, pmeCorrTable, range);
+}
+
+TYPED_TEST(SplineTableTest, TwoFunctions)
+{
+    std::pair<real, real>  range(0.2, 2.0);
+
+    TypeParam              table( {{"LJ6", lj6Function, lj6Derivative}, {"LJ12", lj12Function, lj12Derivative}}, range);
+
+    // Test entire range for each function. This will use the method that interpolates a single function
+    TestFixture::template testSplineTableAgainstFunctions<2, 0>("LJ6", lj6Function, lj6Derivative, table, range);
+    TestFixture::template testSplineTableAgainstFunctions<2, 1>("LJ12", lj12Function, lj12Derivative, table, range);
+
+    // Test the methods that evaluated both functions for one value
+    real     x        = 0.5 * (range.first + range.second);
+    real     refFunc0 = lj6Function(x);
+    real     refDer0  = lj6Derivative(x);
+    real     refFunc1 = lj12Function(x);
+    real     refDer1  = lj12Derivative(x);
+
+    real     tstFunc0, tstDer0, tstFunc1, tstDer1;
+    real     tmpFunc0, tmpFunc1, tmpDer0, tmpDer1;
+
+    // test that we reproduce the reference functions
+    table.evaluateFunctionAndDerivative(x, &tstFunc0, &tstDer0, &tstFunc1, &tstDer1);
+
+    real funcErr0 = std::abs(tstFunc0-refFunc0) / std::abs(refFunc0);
+    real funcErr1 = std::abs(tstFunc1-refFunc1) / std::abs(refFunc1);
+    real derErr0  = std::abs(tstDer0-refDer0) / std::abs(refDer0);
+    real derErr1  = std::abs(tstDer1-refDer1) / std::abs(refDer1);
+
+    // Use asserts, since the following ones compare to these values.
+    ASSERT_LT(funcErr0, TypeParam::defaultTolerance);
+    ASSERT_LT(derErr0, TypeParam::defaultTolerance);
+    ASSERT_LT(funcErr1, TypeParam::defaultTolerance);
+    ASSERT_LT(derErr1, TypeParam::defaultTolerance);
+
+    // Test that function/derivative-only interpolation methods work
+    table.evaluateFunction(x, &tmpFunc0, &tmpFunc1);
+    table.evaluateDerivative(x, &tmpDer0, &tmpDer1);
+    EXPECT_EQ(tstFunc0, tmpFunc0);
+    EXPECT_EQ(tstFunc1, tmpFunc1);
+    EXPECT_EQ(tstDer0, tmpDer0);
+
+    // Test that scrambled order interpolation methods work
+    table.template evaluateFunctionAndDerivative<2, 1, 0>(x, &tstFunc1, &tstDer1, &tstFunc0, &tstDer0);
+    EXPECT_EQ(tstFunc0, tmpFunc0);
+    EXPECT_EQ(tstFunc1, tmpFunc1);
+    EXPECT_EQ(tstDer0, tmpDer0);
+    EXPECT_EQ(tstDer1, tmpDer1);
+
+    // Test scrambled order for function/derivative-only methods
+    table.template evaluateFunction<2, 1, 0>(x, &tmpFunc1, &tmpFunc0);
+    table.template evaluateDerivative<2, 1, 0>(x, &tmpDer1, &tmpDer0);
+    EXPECT_EQ(tstFunc0, tmpFunc0);
+    EXPECT_EQ(tstFunc1, tmpFunc1);
+    EXPECT_EQ(tstDer0, tmpDer0);
+    EXPECT_EQ(tstDer1, tmpDer1);
+}
+
+TYPED_TEST(SplineTableTest, ThreeFunctions)
+{
+    std::pair<real, real>  range(0.2, 2.0);
+
+    TypeParam              table( {{"Coulomb", coulombFunction, coulombDerivative}, {"LJ6", lj6Function, lj6Derivative}, {"LJ12", lj12Function, lj12Derivative}}, range);
+
+    // Test entire range for each function
+    TestFixture::template testSplineTableAgainstFunctions<3, 0>("Coulomb", coulombFunction, coulombDerivative, table, range);
+    TestFixture::template testSplineTableAgainstFunctions<3, 1>("LJ6", lj6Function, lj6Derivative, table, range);
+    TestFixture::template testSplineTableAgainstFunctions<3, 2>("LJ12", lj12Function, lj12Derivative, table, range);
+
+    // Test the methods that evaluated both functions for one value
+    real     x        = 0.5 * (range.first + range.second);
+    real     refFunc0 = coulombFunction(x);
+    real     refDer0  = coulombDerivative(x);
+    real     refFunc1 = lj6Function(x);
+    real     refDer1  = lj6Derivative(x);
+    real     refFunc2 = lj12Function(x);
+    real     refDer2  = lj12Derivative(x);
+
+    real     tstFunc0, tstDer0, tstFunc1, tstDer1, tstFunc2, tstDer2;
+    real     tmpFunc0, tmpFunc1, tmpFunc2, tmpDer0, tmpDer1, tmpDer2;
+
+    // test that we reproduce the reference functions
+    table.evaluateFunctionAndDerivative(x, &tstFunc0, &tstDer0, &tstFunc1, &tstDer1, &tstFunc2, &tstDer2);
+
+    real funcErr0 = std::abs(tstFunc0-refFunc0) / std::abs(refFunc0);
+    real derErr0  = std::abs(tstDer0-refDer0) / std::abs(refDer0);
+    real funcErr1 = std::abs(tstFunc1-refFunc1) / std::abs(refFunc1);
+    real derErr1  = std::abs(tstDer1-refDer1) / std::abs(refDer1);
+    real funcErr2 = std::abs(tstFunc2-refFunc2) / std::abs(refFunc2);
+    real derErr2  = std::abs(tstDer2-refDer2) / std::abs(refDer2);
+
+    // Use asserts, since the following ones compare to these values.
+    ASSERT_LT(funcErr0, TypeParam::defaultTolerance);
+    ASSERT_LT(derErr0, TypeParam::defaultTolerance);
+    ASSERT_LT(funcErr1, TypeParam::defaultTolerance);
+    ASSERT_LT(derErr1, TypeParam::defaultTolerance);
+    ASSERT_LT(funcErr2, TypeParam::defaultTolerance);
+    ASSERT_LT(derErr2, TypeParam::defaultTolerance);
+
+    // Test that function/derivative-only interpolation methods work
+    table.evaluateFunction(x, &tmpFunc0, &tmpFunc1, &tmpFunc2);
+    table.evaluateDerivative(x, &tmpDer0, &tmpDer1, &tmpDer2);
+    EXPECT_EQ(tstFunc0, tmpFunc0);
+    EXPECT_EQ(tstFunc1, tmpFunc1);
+    EXPECT_EQ(tstFunc2, tmpFunc2);
+    EXPECT_EQ(tstDer0, tmpDer0);
+    EXPECT_EQ(tstDer1, tmpDer1);
+    EXPECT_EQ(tstDer2, tmpDer2);
+
+    // Test two functions out of three
+    table.template evaluateFunctionAndDerivative<3, 0, 1>(x, &tmpFunc0, &tmpDer0, &tmpFunc1, &tmpDer1);
+    EXPECT_EQ(tstFunc0, tmpFunc0);
+    EXPECT_EQ(tstFunc1, tmpFunc1);
+    EXPECT_EQ(tstDer0, tmpDer0);
+    EXPECT_EQ(tstDer1, tmpDer1);
+
+    // two out of three, function/derivative-only
+    table.template evaluateFunction<3, 0, 1>(x, &tmpFunc0, &tmpFunc1);
+    table.template evaluateDerivative<3, 0, 1>(x, &tmpDer0, &tmpDer1);
+    EXPECT_EQ(tstFunc0, tmpFunc0);
+    EXPECT_EQ(tstFunc1, tmpFunc1);
+    EXPECT_EQ(tstDer0, tmpDer0);
+    EXPECT_EQ(tstDer1, tmpDer1);
+
+    // Test that scrambled order interpolation methods work
+    table.template evaluateFunctionAndDerivative<3, 2, 1, 0>(x, &tstFunc2, &tstDer2, &tstFunc1, &tstDer1, &tstFunc0, &tstDer0);
+    EXPECT_EQ(tstFunc0, tmpFunc0);
+    EXPECT_EQ(tstFunc1, tmpFunc1);
+    EXPECT_EQ(tstFunc2, tmpFunc2);
+    EXPECT_EQ(tstDer0, tmpDer0);
+    EXPECT_EQ(tstDer1, tmpDer1);
+    EXPECT_EQ(tstDer2, tmpDer2);
+
+    // Test scrambled order for function/derivative-only methods
+    table.template evaluateFunction<3, 2, 1, 0>(x, &tmpFunc2, &tmpFunc1, &tmpFunc0);
+    table.template evaluateDerivative<3, 2, 1, 0>(x, &tmpDer2, &tmpDer1, &tmpDer0);
+    EXPECT_EQ(tstFunc0, tmpFunc0);
+    EXPECT_EQ(tstFunc1, tmpFunc1);
+    EXPECT_EQ(tstFunc2, tmpFunc2);
+    EXPECT_EQ(tstDer0, tmpDer0);
+    EXPECT_EQ(tstDer1, tmpDer1);
+    EXPECT_EQ(tstDer2, tmpDer2);
+}
+
+#if GMX_SIMD_HAVE_REAL
+TYPED_TEST(SplineTableTest, Simd)
+{
+    std::pair<real, real>  range(0.2, 1.0);
+    TypeParam              table( {{"LJ12", lj12Function, lj12Derivative}}, range);
+
+    // We already test that the SIMD operations handle the different elements
+    // correctly in the SIMD module, so here we only test that interpolation
+    // works for a single value in the middle of the interval
+
+    real     x       = 0.5 * (range.first + range.second);
+    real     refFunc = lj12Function(x);
+    real     refDer  = lj12Derivative(x);
+    SimdReal tstFunc, tstDer;
+    real     funcErr, derErr;
+    GMX_ALIGNED(real, GMX_SIMD_REAL_WIDTH) alignedMem[GMX_SIMD_REAL_WIDTH];
+
+    table.evaluateFunctionAndDerivative(SimdReal(x), &tstFunc, &tstDer);
+
+    store(alignedMem, tstFunc);
+    funcErr = std::abs(alignedMem[0]-refFunc) / std::abs(refFunc);
+
+    store(alignedMem, tstDer);
+    derErr  = std::abs(alignedMem[0]-refDer ) / std::abs(refDer );
+
+    EXPECT_LT(funcErr, TypeParam::defaultTolerance);
+    EXPECT_LT(derErr, TypeParam::defaultTolerance);
+}
+
+TYPED_TEST(SplineTableTest, SimdTwoFunctions)
+{
+    std::pair<real, real>  range(0.2, 2.0);
+
+    TypeParam              table( {{"LJ6", lj6Function, lj6Derivative}, {"LJ12", lj12Function, lj12Derivative}}, range);
+
+    // We already test that the SIMD operations handle the different elements
+    // correctly in the SIMD module, so here we only test that interpolation
+    // works for a single value in the middle of the interval
+
+    real     x        = 0.5 * (range.first + range.second);
+    real     refFunc0 = lj6Function(x);
+    real     refDer0  = lj6Derivative(x);
+    real     refFunc1 = lj12Function(x);
+    real     refDer1  = lj12Derivative(x);
+    SimdReal tstFunc0, tstDer0;
+    SimdReal tstFunc1, tstDer1;
+    real     funcErr0, derErr0;
+    real     funcErr1, derErr1;
+    GMX_ALIGNED(real, GMX_SIMD_REAL_WIDTH) alignedMem[GMX_SIMD_REAL_WIDTH];
+
+    table.evaluateFunctionAndDerivative(SimdReal(x), &tstFunc0, &tstDer0, &tstFunc1, &tstDer1);
+
+    store(alignedMem, tstFunc0);
+    funcErr0 = std::abs(alignedMem[0]-refFunc0) / std::abs(refFunc0);
+
+    store(alignedMem, tstDer0);
+    derErr0  = std::abs(alignedMem[0]-refDer0 ) / std::abs(refDer0 );
+
+    store(alignedMem, tstFunc1);
+    funcErr1 = std::abs(alignedMem[0]-refFunc1) / std::abs(refFunc1);
+
+    store(alignedMem, tstDer1);
+    derErr1  = std::abs(alignedMem[0]-refDer1 ) / std::abs(refDer1 );
+
+    EXPECT_LT(funcErr0, TypeParam::defaultTolerance);
+    EXPECT_LT(derErr0, TypeParam::defaultTolerance);
+    EXPECT_LT(funcErr1, TypeParam::defaultTolerance);
+    EXPECT_LT(derErr1, TypeParam::defaultTolerance);
+}
+#endif
+
+#if GMX_SIMD_HAVE_REAL && !defined NDEBUG
+TYPED_TEST(SplineTableTest, CatchesOutOfRangeValuesSimd)
+{
+    std::pair<real, real>  range(0.2, 1.0);
+    TypeParam              table( {{"LJ12", lj12Function, lj12Derivative}}, range);
+    SimdReal               x, func, der;
+
+    GMX_ALIGNED(real, GMX_SIMD_REAL_WIDTH) alignedMem[GMX_SIMD_REAL_WIDTH];
+
+    // Make position 1 incorrect if width>=2, otherwise position 0
+    alignedMem[ (GMX_SIMD_REAL_WIDTH >= 2) ? 1 : 0] = -GMX_REAL_EPS;
+    x = load(alignedMem);
+
+    EXPECT_THROW_GMX(table.evaluateFunctionAndDerivative(x, &func, &der), gmx::RangeError);
+
+    for (std::size_t i = 0; i < GMX_SIMD_REAL_WIDTH; i++)
+    {
+        alignedMem[i] = range.second*(1.0-GMX_REAL_EPS);
+    }
+    // Make position 1 incorrect if width>=2, otherwise position 0
+    alignedMem[ (GMX_SIMD_REAL_WIDTH >= 2) ? 1 : 0] = range.second;
+    x = load(alignedMem);
+
+    EXPECT_THROW_GMX(table.evaluateFunctionAndDerivative(x, &func, &der), gmx::RangeError);
+}
+#endif
+
+} // namespace
+
+} // namespace test
+
+} // namespace gmx
index 548827df384d3c35edc81dea1c689b1d952a610f..7b9ab440a2dfc5b3be1a631a298d571ea900782d 100644 (file)
@@ -44,7 +44,6 @@
 
 #include <array>
 
-#include "gromacs/gmxlib/md_logging.h"
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/timing/cyclecounter.h"
 #include "gromacs/timing/gpu_timing.h"
@@ -52,6 +51,7 @@
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/gmxmpi.h"
+#include "gromacs/utility/logger.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/snprintf.h"
 
@@ -710,7 +710,7 @@ static void print_header(FILE *fplog, int nrank_pp, int nth_pp, int nrank_pme, i
 }
 
 
-void wallcycle_print(FILE *fplog, int nnodes, int npme,
+void wallcycle_print(FILE *fplog, const gmx::MDLogger &mdlog, int nnodes, int npme,
                      int nth_pp, int nth_pme, double realtime,
                      gmx_wallcycle_t wc, const WallcycleCounts &cyc_sum,
                      struct gmx_wallclock_gpu_t *gpu_t)
@@ -751,14 +751,15 @@ void wallcycle_print(FILE *fplog, int nnodes, int npme,
            timing data might still be sensible for some non-Jenkins
            run, than is lost from diagnosing Jenkins FP exceptions on
            runs about whose execution time we don't care. */
-        md_print_warn(NULL, fplog, "WARNING: A total of %f CPU cycles was recorded, so mdrun cannot print a time accounting\n", tot);
+        GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                "WARNING: A total of %f CPU cycles was recorded, so mdrun cannot print a time accounting",
+                tot);
         return;
     }
 
     if (wc->haveInvalidCount)
     {
-        md_print_warn(NULL, fplog, "%s\n",
-                      "NOTE: Detected invalid cycle counts, probably because threads moved between CPU cores that do not have synchronized cycle counters. Will not print the cycle accounting.");
+        GMX_LOG(mdlog.warning).asParagraph().appendText("NOTE: Detected invalid cycle counts, probably because threads moved between CPU cores that do not have synchronized cycle counters. Will not print the cycle accounting.");
         return;
     }
 
@@ -948,26 +949,26 @@ void wallcycle_print(FILE *fplog, int nnodes, int npme,
                         /* The user could have used -notunepme,
                          * but we currently can't check that here.
                          */
-                        md_print_warn(NULL, fplog,
-                                      "\nNOTE: The GPU has >25%% less load than the CPU. This imbalance causes\n"
-                                      "      performance loss. Maybe the domain decomposition limits the PME tuning.\n"
-                                      "      In that case, try setting the DD grid manually (-dd) or lowering -dds.");
+                        GMX_LOG(mdlog.warning).asParagraph().appendText(
+                                "NOTE: The GPU has >25% less load than the CPU. This imbalance causes\n"
+                                "      performance loss. Maybe the domain decomposition limits the PME tuning.\n"
+                                "      In that case, try setting the DD grid manually (-dd) or lowering -dds.");
                     }
                     else
                     {
                         /* We should not end up here, unless the box is
                          * too small for increasing the cut-off for PME tuning.
                          */
-                        md_print_warn(NULL, fplog,
-                                      "\nNOTE: The GPU has >25%% less load than the CPU. This imbalance causes\n"
-                                      "      performance loss.");
+                        GMX_LOG(mdlog.warning).asParagraph().appendText(
+                                "NOTE: The GPU has >25% less load than the CPU. This imbalance causes\n"
+                                "      performance loss.");
                     }
                 }
                 if (gpu_cpu_ratio > 1.2)
                 {
-                    md_print_warn(NULL, fplog,
-                                  "\nNOTE: The GPU has >20%% more load than the CPU. This imbalance causes\n"
-                                  "      performance loss, consider using a shorter cut-off and a finer PME grid.");
+                    GMX_LOG(mdlog.warning).asParagraph().appendText(
+                            "NOTE: The GPU has >20% more load than the CPU. This imbalance causes\n"
+                            "      performance loss, consider using a shorter cut-off and a finer PME grid.");
                 }
             }
         }
@@ -975,9 +976,9 @@ void wallcycle_print(FILE *fplog, int nnodes, int npme,
 
     if (wc->wc_barrier)
     {
-        md_print_warn(NULL, fplog,
-                      "MPI_Barrier was called before each cycle start/stop\n"
-                      "call, so timings are not those of real runs.\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText(
+                "MPI_Barrier was called before each cycle start/stop\n"
+                "call, so timings are not those of real runs.");
     }
 
     if (wc->wcc[ewcNB_XF_BUF_OPS].n > 0 &&
@@ -987,29 +988,28 @@ void wallcycle_print(FILE *fplog, int nnodes, int npme,
         /* Only the sim master calls this function, so always print to stderr */
         if (wc->wcc[ewcDOMDEC].n == 0)
         {
-            md_print_warn(NULL, fplog,
-                          "NOTE: %d %% of the run time was spent in pair search,\n"
-                          "      you might want to increase nstlist (this has no effect on accuracy)\n",
-                          (int)(100*cyc_sum[ewcNS]/tot+0.5));
+            GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                    "NOTE: %d %% of the run time was spent in pair search,\n"
+                    "      you might want to increase nstlist (this has no effect on accuracy)\n",
+                    (int)(100*cyc_sum[ewcNS]/tot+0.5));
         }
         else
         {
-            md_print_warn(NULL, fplog,
-                          "NOTE: %d %% of the run time was spent in domain decomposition,\n"
-                          "      %d %% of the run time was spent in pair search,\n"
-                          "      you might want to increase nstlist (this has no effect on accuracy)\n",
-                          (int)(100*cyc_sum[ewcDOMDEC]/tot+0.5),
-                          (int)(100*cyc_sum[ewcNS]/tot+0.5));
+            GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                    "NOTE: %d %% of the run time was spent in domain decomposition,\n"
+                    "      %d %% of the run time was spent in pair search,\n"
+                    "      you might want to increase nstlist (this has no effect on accuracy)\n",
+                    (int)(100*cyc_sum[ewcDOMDEC]/tot+0.5),
+                    (int)(100*cyc_sum[ewcNS]/tot+0.5));
         }
     }
 
     if (cyc_sum[ewcMoveE] > tot*0.05)
     {
-        /* Only the sim master calls this function, so always print to stderr */
-        md_print_warn(NULL, fplog,
-                      "NOTE: %d %% of the run time was spent communicating energies,\n"
-                      "      you might want to use the -gcom option of mdrun\n",
-                      (int)(100*cyc_sum[ewcMoveE]/tot+0.5));
+        GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                "NOTE: %d %% of the run time was spent communicating energies,\n"
+                "      you might want to use the -gcom option of mdrun\n",
+                (int)(100*cyc_sum[ewcMoveE]/tot+0.5));
     }
 }
 
index d3c316da592d8554e736b503e20697b525e28546..e84243fe8ca5f5e75a8d6896ef2f2c8875e5b11e 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2008, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 
 #include "gromacs/utility/basedefinitions.h"
 
+struct t_commrec;
+
+namespace gmx
+{
+class MDLogger;
+}
+
 typedef struct gmx_wallcycle *gmx_wallcycle_t;
 typedef struct gmx_wallclock_gpu_t gmx_wallclock_gpu_t;
-struct t_commrec;
 
 typedef std::array<double, ewcNR+ewcsNR> WallcycleCounts;
 /* Convenience typedef */
@@ -57,7 +63,7 @@ WallcycleCounts wallcycle_sum(struct t_commrec *cr, gmx_wallcycle_t wc);
 /* Return a vector of the sum of cycle counts over the nodes in
    cr->mpi_comm_mysim. */
 
-void wallcycle_print(FILE *fplog, int nnodes, int npme,
+void wallcycle_print(FILE *fplog, const gmx::MDLogger &mdlog, int nnodes, int npme,
                      int nth_pp, int nth_pme, double realtime,
                      gmx_wallcycle_t wc, const WallcycleCounts &cyc_sum,
                      struct gmx_wallclock_gpu_t *gpu_t);
index bfcbf1d294cd28349c9483d850168e5a1b8911d7..4beac915f7c2e76998b7aa28860418ac54dee584 100644 (file)
@@ -200,7 +200,7 @@ gmx_gettime()
        headers claim sufficient support for POSIX (ie not Mac and
        Windows), and it isn't BG/Q (whose compute node kernel only
        supports gettimeofday, and bgclang doesn't provide a fully
-       functional implementation clock_gettime, unlike xlc). */
+       functional implementation clock_gettime). */
 #if HAVE_CLOCK_GETTIME && defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && !(defined __bgq__ && defined __clang__)
     struct timespec t;
     double          seconds;
@@ -237,7 +237,7 @@ gmx_gettime_per_thread()
        headers claim sufficient support for POSIX (ie not Mac and
        Windows), and it isn't BG/Q (whose compute node kernel only
        supports gettimeofday, and bgclang doesn't provide a fully
-       functional implementation clock_gettime, unlike xlc). */
+       functional implementation clock_gettime). */
 #if HAVE_CLOCK_GETTIME && defined(_POSIX_THREAD_CPUTIME) && _POSIX_THREAD_CPUTIME > 0 && !(defined __bgq__ && defined __clang__)
     struct timespec t;
     double          seconds;
index 17778e9b3b54a9eca520c09cc19a8a51b7fdb8d6..d2fbd6998484feb45cb4c4d1e4616696946abd12 100644 (file)
 #include "gromacs/math/functions.h"
 #include "gromacs/math/units.h"
 #include "gromacs/math/vec.h"
+#include "gromacs/mdrunutility/mdmodules.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/pbcutil/pbc.h"
-#include "gromacs/tools/compare.h"
 #include "gromacs/topology/atomprop.h"
 #include "gromacs/topology/block.h"
 #include "gromacs/topology/ifunc.h"
@@ -86,11 +86,109 @@ typedef struct {
     float bBox;
 } t_fr_time;
 
+static void comp_tpx(const char *fn1, const char *fn2,
+                     gmx_bool bRMSD, real ftol, real abstol)
+{
+    const char    *ff[2];
+    gmx::MDModules mdModules[2];
+    t_inputrec    *ir[2] = { mdModules[0].inputrec(), mdModules[1].inputrec() };
+    t_state        state[2];
+    gmx_mtop_t     mtop[2];
+    t_topology     top[2];
+    int            i;
+
+    ff[0] = fn1;
+    ff[1] = fn2;
+    for (i = 0; i < (fn2 ? 2 : 1); i++)
+    {
+        read_tpx_state(ff[i], ir[i], &state[i], &(mtop[i]));
+    }
+    if (fn2)
+    {
+        cmp_inputrec(stdout, ir[0], ir[1], ftol, abstol);
+        /* Convert gmx_mtop_t to t_topology.
+         * We should implement direct mtop comparison,
+         * but it might be useful to keep t_topology comparison as an option.
+         */
+        top[0] = gmx_mtop_t_to_t_topology(&mtop[0], false);
+        top[1] = gmx_mtop_t_to_t_topology(&mtop[1], false);
+        cmp_top(stdout, &top[0], &top[1], ftol, abstol);
+        cmp_groups(stdout, &mtop[0].groups, &mtop[1].groups,
+                   mtop[0].natoms, mtop[1].natoms);
+        comp_state(&state[0], &state[1], bRMSD, ftol, abstol);
+    }
+    else
+    {
+        if (ir[0]->efep == efepNO)
+        {
+            fprintf(stdout, "inputrec->efep = %s\n", efep_names[ir[0]->efep]);
+        }
+        else
+        {
+            if (ir[0]->bPull)
+            {
+                comp_pull_AB(stdout, ir[0]->pull, ftol, abstol);
+            }
+            /* Convert gmx_mtop_t to t_topology.
+             * We should implement direct mtop comparison,
+             * but it might be useful to keep t_topology comparison as an option.
+             */
+            top[0] = gmx_mtop_t_to_t_topology(&mtop[0], true);
+            cmp_top(stdout, &top[0], NULL, ftol, abstol);
+        }
+    }
+}
+
+static void comp_trx(const gmx_output_env_t *oenv, const char *fn1, const char *fn2,
+                     gmx_bool bRMSD, real ftol, real abstol)
+{
+    int          i;
+    const char  *fn[2];
+    t_trxframe   fr[2];
+    t_trxstatus *status[2];
+    gmx_bool     b[2];
+
+    fn[0] = fn1;
+    fn[1] = fn2;
+    fprintf(stderr, "Comparing trajectory files %s and %s\n", fn1, fn2);
+    for (i = 0; i < 2; i++)
+    {
+        b[i] = read_first_frame(oenv, &status[i], fn[i], &fr[i], TRX_READ_X|TRX_READ_V|TRX_READ_F);
+    }
+
+    if (b[0] && b[1])
+    {
+        do
+        {
+            comp_frame(stdout, &(fr[0]), &(fr[1]), bRMSD, ftol, abstol);
+
+            for (i = 0; i < 2; i++)
+            {
+                b[i] = read_next_frame(oenv, status[i], &fr[i]);
+            }
+        }
+        while (b[0] && b[1]);
+
+        for (i = 0; i < 2; i++)
+        {
+            if (b[i] && !b[1-i])
+            {
+                fprintf(stdout, "\nEnd of file on %s but not on %s\n", fn[1-i], fn[i]);
+            }
+            close_trj(status[i]);
+        }
+    }
+    if (!b[0] && !b[1])
+    {
+        fprintf(stdout, "\nBoth files read correctly\n");
+    }
+}
+
 static void tpx2system(FILE *fp, const gmx_mtop_t *mtop)
 {
     int                       nmol, nvsite = 0;
     gmx_mtop_atomloop_block_t aloop;
-    t_atom                   *atom;
+    const t_atom             *atom;
 
     fprintf(fp, "\\subsection{Simulation system}\n");
     aloop = gmx_mtop_atomloop_block_init(mtop);
@@ -146,16 +244,18 @@ static void tpx2params(FILE *fp, const t_inputrec *ir)
 
 static void tpx2methods(const char *tpx, const char *tex)
 {
-    FILE         *fp;
-    t_inputrec    ir;
-    t_state       state;
-    gmx_mtop_t    mtop;
-
-    read_tpx_state(tpx, &ir, &state, &mtop);
+    FILE          *fp;
+    t_inputrec    *ir;
+    t_state        state;
+    gmx_mtop_t     mtop;
+
+    gmx::MDModules mdModules;
+    ir = mdModules.inputrec();
+    read_tpx_state(tpx, ir, &state, &mtop);
     fp = gmx_fio_fopen(tex, "w");
     fprintf(fp, "\\section{Methods}\n");
     tpx2system(fp, &mtop);
-    tpx2params(fp, &ir);
+    tpx2params(fp, ir);
     gmx_fio_fclose(fp);
 }
 
@@ -288,12 +388,14 @@ void chk_trj(const gmx_output_env_t *oenv, const char *fn, const char *tpr, real
     gmx_mtop_t       mtop;
     gmx_localtop_t  *top = NULL;
     t_state          state;
-    t_inputrec       ir;
+    t_inputrec      *ir;
 
+    gmx::MDModules   mdModules;
+    ir = mdModules.inputrec();
     if (tpr)
     {
-        read_tpx_state(tpr, &ir, &state, &mtop);
-        top = gmx_mtop_generate_local_top(&mtop, ir.efep != efepNO);
+        read_tpx_state(tpr, ir, &state, &mtop);
+        top = gmx_mtop_generate_local_top(&mtop, ir->efep != efepNO);
     }
     new_natoms = -1;
     natoms     = -1;
@@ -360,7 +462,7 @@ void chk_trj(const gmx_output_env_t *oenv, const char *fn, const char *tpr, real
         natoms = new_natoms;
         if (tpr)
         {
-            chk_bonds(&top->idef, ir.ePBC, fr.x, fr.box, tol);
+            chk_bonds(&top->idef, ir->ePBC, fr.x, fr.box, tol);
         }
         if (fr.bX)
         {
diff --git a/src/gromacs/tools/compare.cpp b/src/gromacs/tools/compare.cpp
deleted file mode 100644 (file)
index b7313c5..0000000
+++ /dev/null
@@ -1,1469 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
- * and including many others, as listed in the AUTHORS file in the
- * top-level source directory and at http://www.gromacs.org.
- *
- * GROMACS is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * GROMACS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with GROMACS; if not, see
- * http://www.gnu.org/licenses, or write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
- *
- * If you want to redistribute modifications to GROMACS, please
- * consider that scientific software is very special. Version
- * control is crucial - bugs must be traceable. We will be happy to
- * consider code for inclusion in the official distribution, but
- * derived work must not be called official GROMACS. Details are found
- * in the README & COPYING files - if they are missing, get the
- * official version at http://www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the research papers on the package. Check out http://www.gromacs.org.
- */
-/* This file is completely threadsafe - keep it that way! */
-
-#include "gmxpre.h"
-
-#include <cmath>
-#include <cstdio>
-#include <cstring>
-
-#include <algorithm>
-
-#include "gromacs/fileio/enxio.h"
-#include "gromacs/fileio/tpxio.h"
-#include "gromacs/fileio/trxio.h"
-#include "gromacs/mdtypes/inputrec.h"
-#include "gromacs/mdtypes/md_enums.h"
-#include "gromacs/mdtypes/pull-params.h"
-#include "gromacs/topology/ifunc.h"
-#include "gromacs/topology/mtop_util.h"
-#include "gromacs/topology/topology.h"
-#include "gromacs/trajectory/trajectoryframe.h"
-#include "gromacs/utility/cstringutil.h"
-#include "gromacs/utility/fatalerror.h"
-#include "gromacs/utility/futil.h"
-#include "gromacs/utility/smalloc.h"
-#include "gromacs/utility/stringutil.h"
-
-static void cmp_int(FILE *fp, const char *s, int index, int i1, int i2)
-{
-    if (i1 != i2)
-    {
-        if (index != -1)
-        {
-            fprintf(fp, "%s[%d] (%d - %d)\n", s, index, i1, i2);
-        }
-        else
-        {
-            fprintf(fp, "%s (%d - %d)\n", s, i1, i2);
-        }
-    }
-}
-
-static void cmp_int64(FILE *fp, const char *s, gmx_int64_t i1, gmx_int64_t i2)
-{
-    if (i1 != i2)
-    {
-        fprintf(fp, "%s (", s);
-        fprintf(fp, "%" GMX_PRId64, i1);
-        fprintf(fp, " - ");
-        fprintf(fp, "%" GMX_PRId64, i2);
-        fprintf(fp, ")\n");
-    }
-}
-
-static void cmp_us(FILE *fp, const char *s, int index, unsigned short i1, unsigned short i2)
-{
-    if (i1 != i2)
-    {
-        if (index != -1)
-        {
-            fprintf(fp, "%s[%d] (%hu - %hu)\n", s, index, i1, i2);
-        }
-        else
-        {
-            fprintf(fp, "%s (%hu - %hu)\n", s, i1, i2);
-        }
-    }
-}
-
-static void cmp_uc(FILE *fp, const char *s, int index, unsigned char i1, unsigned char i2)
-{
-    if (i1 != i2)
-    {
-        if (index != -1)
-        {
-            fprintf(fp, "%s[%d] (%d - %d)\n", s, index, i1, i2);
-        }
-        else
-        {
-            fprintf(fp, "%s (%d - %d)\n", s, i1, i2);
-        }
-    }
-}
-
-static gmx_bool cmp_bool(FILE *fp, const char *s, int index, gmx_bool b1, gmx_bool b2)
-{
-    if (b1)
-    {
-        b1 = 1;
-    }
-    else
-    {
-        b1 = 0;
-    }
-    if (b2)
-    {
-        b2 = 1;
-    }
-    else
-    {
-        b2 = 0;
-    }
-    if (b1 != b2)
-    {
-        if (index != -1)
-        {
-            fprintf(fp, "%s[%d] (%s - %s)\n", s, index,
-                    gmx::boolToString(b1), gmx::boolToString(b2));
-        }
-        else
-        {
-            fprintf(fp, "%s (%s - %s)\n", s,
-                    gmx::boolToString(b1), gmx::boolToString(b2));
-        }
-    }
-    return b1 && b2;
-}
-
-static void cmp_str(FILE *fp, const char *s, int index,
-                    const char *s1, const char *s2)
-{
-    if (std::strcmp(s1, s2) != 0)
-    {
-        if (index != -1)
-        {
-            fprintf(fp, "%s[%d] (%s - %s)\n", s, index, s1, s2);
-        }
-        else
-        {
-            fprintf(fp, "%s (%s - %s)\n", s, s1, s2);
-        }
-    }
-}
-
-static gmx_bool equal_real(real i1, real i2, real ftol, real abstol)
-{
-    return ( ( 2*fabs(i1 - i2) <= (fabs(i1) + fabs(i2))*ftol ) || fabs(i1-i2) <= abstol );
-}
-
-static gmx_bool equal_float(float i1, float i2, float ftol, float abstol)
-{
-    return ( ( 2*fabs(i1 - i2) <= (fabs(i1) + fabs(i2))*ftol ) || fabs(i1-i2) <= abstol );
-}
-
-static gmx_bool equal_double(double i1, double i2, real ftol, real abstol)
-{
-    return ( ( 2*fabs(i1 - i2) <= (fabs(i1) + fabs(i2))*ftol ) || fabs(i1-i2) <= abstol );
-}
-
-static void
-cmp_real(FILE *fp, const char *s, int index, real i1, real i2, real ftol, real abstol)
-{
-    if (!equal_real(i1, i2, ftol, abstol))
-    {
-        if (index != -1)
-        {
-            fprintf(fp, "%s[%2d] (%e - %e)\n", s, index, i1, i2);
-        }
-        else
-        {
-            fprintf(fp, "%s (%e - %e)\n", s, i1, i2);
-        }
-    }
-}
-
-static void
-cmp_float(FILE *fp, const char *s, int index, float i1, float i2, float ftol, float abstol)
-{
-    if (!equal_float(i1, i2, ftol, abstol))
-    {
-        if (index != -1)
-        {
-            fprintf(fp, "%s[%2d] (%e - %e)\n", s, index, i1, i2);
-        }
-        else
-        {
-            fprintf(fp, "%s (%e - %e)\n", s, i1, i2);
-        }
-    }
-}
-
-
-
-static void
-cmp_double(FILE *fp, const char *s, int index, double i1, double i2, double ftol, double abstol)
-{
-    if (!equal_double(i1, i2, ftol, abstol))
-    {
-        if (index != -1)
-        {
-            fprintf(fp, "%s[%2d] (%16.9e - %16.9e)\n", s, index, i1, i2);
-        }
-        else
-        {
-            fprintf(fp, "%s (%16.9e - %16.9e)\n", s, i1, i2);
-        }
-    }
-}
-
-static void cmp_rvec(FILE *fp, const char *s, int index, const rvec i1, const rvec i2, real ftol, real abstol)
-{
-    if (!equal_real(i1[XX], i2[XX], ftol, abstol) ||
-        !equal_real(i1[YY], i2[YY], ftol, abstol) ||
-        !equal_real(i1[ZZ], i2[ZZ], ftol, abstol))
-    {
-        if (index != -1)
-        {
-            fprintf(fp, "%s[%5d] (%12.5e %12.5e %12.5e) - (%12.5e %12.5e %12.5e)\n",
-                    s, index, i1[XX], i1[YY], i1[ZZ], i2[XX], i2[YY], i2[ZZ]);
-        }
-        else
-        {
-            fprintf(fp, "%s (%12.5e %12.5e %12.5e) - (%12.5e %12.5e %12.5e)\n",
-                    s, i1[XX], i1[YY], i1[ZZ], i2[XX], i2[YY], i2[ZZ]);
-        }
-    }
-}
-
-static void cmp_ivec(FILE *fp, const char *s, int index, const ivec i1, const ivec i2)
-{
-    if ((i1[XX] != i2[XX]) || (i1[YY] != i2[YY]) || (i1[ZZ] != i2[ZZ]))
-    {
-        if (index != -1)
-        {
-            fprintf(fp, "%s[%5d] (%8d,%8d,%8d - %8d,%8d,%8d)\n", s, index,
-                    i1[XX], i1[YY], i1[ZZ], i2[XX], i2[YY], i2[ZZ]);
-        }
-        else
-        {
-            fprintf(fp, "%s (%8d,%8d,%8d - %8d,%8d,%8d)\n", s,
-                    i1[XX], i1[YY], i1[ZZ], i2[XX], i2[YY], i2[ZZ]);
-        }
-    }
-}
-
-static void cmp_ilist(FILE *fp, int ftype, const t_ilist *il1, const t_ilist *il2)
-{
-    int  i;
-    char buf[256];
-
-    fprintf(fp, "comparing ilist %s\n", interaction_function[ftype].name);
-    sprintf(buf, "%s->nr", interaction_function[ftype].name);
-    cmp_int(fp, buf, -1, il1->nr, il2->nr);
-    sprintf(buf, "%s->iatoms", interaction_function[ftype].name);
-    if (((il1->nr > 0) && (!il1->iatoms)) ||
-        ((il2->nr > 0) && (!il2->iatoms)) ||
-        ((il1->nr != il2->nr)))
-    {
-        fprintf(fp, "Comparing radically different topologies - %s is different\n",
-                buf);
-    }
-    else
-    {
-        for (i = 0; (i < il1->nr); i++)
-        {
-            cmp_int(fp, buf, i, il1->iatoms[i], il2->iatoms[i]);
-        }
-    }
-}
-
-void cmp_iparm(FILE *fp, const char *s, t_functype ft,
-               const t_iparams &ip1, const t_iparams &ip2, real ftol, real abstol)
-{
-    int      i;
-    gmx_bool bDiff;
-
-    bDiff = FALSE;
-    for (i = 0; i < MAXFORCEPARAM && !bDiff; i++)
-    {
-        bDiff = !equal_real(ip1.generic.buf[i], ip2.generic.buf[i], ftol, abstol);
-    }
-    if (bDiff)
-    {
-        fprintf(fp, "%s1: ", s);
-        pr_iparams(fp, ft, &ip1);
-        fprintf(fp, "%s2: ", s);
-        pr_iparams(fp, ft, &ip2);
-    }
-}
-
-void cmp_iparm_AB(FILE *fp, const char *s, t_functype ft, const t_iparams &ip1, real ftol, real abstol)
-{
-    int      nrfpA, nrfpB, p0, i;
-    gmx_bool bDiff;
-
-    /* Normally the first parameter is perturbable */
-    p0    = 0;
-    nrfpA = interaction_function[ft].nrfpA;
-    nrfpB = interaction_function[ft].nrfpB;
-    if (ft == F_PDIHS)
-    {
-        nrfpB = 2;
-    }
-    else if (interaction_function[ft].flags & IF_TABULATED)
-    {
-        /* For tabulated interactions only the second parameter is perturbable */
-        p0    = 1;
-        nrfpB = 1;
-    }
-    bDiff = FALSE;
-    for (i = 0; i < nrfpB && !bDiff; i++)
-    {
-        bDiff = !equal_real(ip1.generic.buf[p0+i], ip1.generic.buf[nrfpA+i], ftol, abstol);
-    }
-    if (bDiff)
-    {
-        fprintf(fp, "%s: ", s);
-        pr_iparams(fp, ft, &ip1);
-    }
-}
-
-static void cmp_cmap(FILE *fp, const gmx_cmap_t *cmap1, const gmx_cmap_t *cmap2, real ftol, real abstol)
-{
-    cmp_int(fp, "cmap ngrid", -1, cmap1->ngrid, cmap2->ngrid);
-    cmp_int(fp, "cmap grid_spacing", -1, cmap1->grid_spacing, cmap2->grid_spacing);
-    if (cmap1->ngrid == cmap2->ngrid &&
-        cmap1->grid_spacing == cmap2->grid_spacing)
-    {
-        int g;
-
-        for (g = 0; g < cmap1->ngrid; g++)
-        {
-            int i;
-
-            fprintf(fp, "comparing cmap %d\n", g);
-
-            for (i = 0; i < 4*cmap1->grid_spacing*cmap1->grid_spacing; i++)
-            {
-                cmp_real(fp, "", i, cmap1->cmapdata[g].cmap[i], cmap2->cmapdata[g].cmap[i], ftol, abstol);
-            }
-        }
-    }
-}
-
-static void cmp_idef(FILE *fp, const t_idef *id1, const t_idef *id2, real ftol, real abstol)
-{
-    int  i;
-    char buf1[64], buf2[64];
-
-    fprintf(fp, "comparing idef\n");
-    if (id2)
-    {
-        cmp_int(fp, "idef->ntypes", -1, id1->ntypes, id2->ntypes);
-        cmp_int(fp, "idef->atnr",  -1, id1->atnr, id2->atnr);
-        for (i = 0; (i < std::min(id1->ntypes, id2->ntypes)); i++)
-        {
-            sprintf(buf1, "idef->functype[%d]", i);
-            sprintf(buf2, "idef->iparam[%d]", i);
-            cmp_int(fp, buf1, i, (int)id1->functype[i], (int)id2->functype[i]);
-            cmp_iparm(fp, buf2, id1->functype[i],
-                      id1->iparams[i], id2->iparams[i], ftol, abstol);
-        }
-        cmp_real(fp, "fudgeQQ", -1, id1->fudgeQQ, id2->fudgeQQ, ftol, abstol);
-        cmp_cmap(fp, &id1->cmap_grid, &id2->cmap_grid, ftol, abstol);
-        for (i = 0; (i < F_NRE); i++)
-        {
-            cmp_ilist(fp, i, &(id1->il[i]), &(id2->il[i]));
-        }
-    }
-    else
-    {
-        for (i = 0; (i < id1->ntypes); i++)
-        {
-            cmp_iparm_AB(fp, "idef->iparam", id1->functype[i], id1->iparams[i], ftol, abstol);
-        }
-    }
-}
-
-static void cmp_block(FILE *fp, const t_block *b1, const t_block *b2, const char *s)
-{
-    char buf[32];
-
-    fprintf(fp, "comparing block %s\n", s);
-    sprintf(buf, "%s.nr", s);
-    cmp_int(fp, buf, -1, b1->nr, b2->nr);
-}
-
-static void cmp_blocka(FILE *fp, const t_blocka *b1, const t_blocka *b2, const char *s)
-{
-    char buf[32];
-
-    fprintf(fp, "comparing blocka %s\n", s);
-    sprintf(buf, "%s.nr", s);
-    cmp_int(fp, buf, -1, b1->nr, b2->nr);
-    sprintf(buf, "%s.nra", s);
-    cmp_int(fp, buf, -1, b1->nra, b2->nra);
-}
-
-static void cmp_atom(FILE *fp, int index, const t_atom *a1, const t_atom *a2, real ftol, real abstol)
-{
-    if (a2)
-    {
-        cmp_us(fp, "atom.type", index, a1->type, a2->type);
-        cmp_us(fp, "atom.ptype", index, a1->ptype, a2->ptype);
-        cmp_int(fp, "atom.resind", index, a1->resind, a2->resind);
-        cmp_int(fp, "atom.atomnumber", index, a1->atomnumber, a2->atomnumber);
-        cmp_real(fp, "atom.m", index, a1->m, a2->m, ftol, abstol);
-        cmp_real(fp, "atom.q", index, a1->q, a2->q, ftol, abstol);
-        cmp_us(fp, "atom.typeB", index, a1->typeB, a2->typeB);
-        cmp_real(fp, "atom.mB", index, a1->mB, a2->mB, ftol, abstol);
-        cmp_real(fp, "atom.qB", index, a1->qB, a2->qB, ftol, abstol);
-    }
-    else
-    {
-        cmp_us(fp, "atom.type", index, a1->type, a1->typeB);
-        cmp_real(fp, "atom.m", index, a1->m, a1->mB, ftol, abstol);
-        cmp_real(fp, "atom.q", index, a1->q, a1->qB, ftol, abstol);
-    }
-}
-
-static void cmp_atoms(FILE *fp, const t_atoms *a1, const t_atoms *a2, real ftol, real abstol)
-{
-    int i;
-
-    fprintf(fp, "comparing atoms\n");
-
-    if (a2)
-    {
-        cmp_int(fp, "atoms->nr", -1, a1->nr, a2->nr);
-        for (i = 0; (i < a1->nr); i++)
-        {
-            cmp_atom(fp, i, &(a1->atom[i]), &(a2->atom[i]), ftol, abstol);
-        }
-    }
-    else
-    {
-        for (i = 0; (i < a1->nr); i++)
-        {
-            cmp_atom(fp, i, &(a1->atom[i]), NULL, ftol, abstol);
-        }
-    }
-}
-
-static void cmp_top(FILE *fp, const t_topology *t1, const t_topology *t2, real ftol, real abstol)
-{
-    fprintf(fp, "comparing top\n");
-    if (t2)
-    {
-        cmp_idef(fp, &(t1->idef), &(t2->idef), ftol, abstol);
-        cmp_atoms(fp, &(t1->atoms), &(t2->atoms), ftol, abstol);
-        cmp_block(fp, &t1->cgs, &t2->cgs, "cgs");
-        cmp_block(fp, &t1->mols, &t2->mols, "mols");
-        cmp_bool(fp, "bIntermolecularInteractions", -1, t1->bIntermolecularInteractions, t2->bIntermolecularInteractions);
-        cmp_blocka(fp, &t1->excls, &t2->excls, "excls");
-    }
-    else
-    {
-        cmp_idef(fp, &(t1->idef), NULL, ftol, abstol);
-        cmp_atoms(fp, &(t1->atoms), NULL, ftol, abstol);
-    }
-}
-
-static void cmp_groups(FILE *fp, const gmx_groups_t *g0, const gmx_groups_t *g1,
-                       int natoms0, int natoms1)
-{
-    int  i, j;
-    char buf[32];
-
-    fprintf(fp, "comparing groups\n");
-
-    for (i = 0; i < egcNR; i++)
-    {
-        sprintf(buf, "grps[%d].nr", i);
-        cmp_int(fp, buf, -1, g0->grps[i].nr, g1->grps[i].nr);
-        if (g0->grps[i].nr == g1->grps[i].nr)
-        {
-            for (j = 0; j < g0->grps[i].nr; j++)
-            {
-                sprintf(buf, "grps[%d].name[%d]", i, j);
-                cmp_str(fp, buf, -1,
-                        *g0->grpname[g0->grps[i].nm_ind[j]],
-                        *g1->grpname[g1->grps[i].nm_ind[j]]);
-            }
-        }
-        cmp_int(fp, "ngrpnr", i, g0->ngrpnr[i], g1->ngrpnr[i]);
-        if (g0->ngrpnr[i] == g1->ngrpnr[i] && natoms0 == natoms1 &&
-            (g0->grpnr[i] != NULL || g1->grpnr[i] != NULL))
-        {
-            for (j = 0; j < natoms0; j++)
-            {
-                cmp_int(fp, gtypes[i], j, ggrpnr(g0, i, j), ggrpnr(g1, i, j));
-            }
-        }
-    }
-    /* We have compared the names in the groups lists,
-     * so we can skip the grpname list comparison.
-     */
-}
-
-static void cmp_rvecs_rmstol(FILE *fp, const char *title, int n, const rvec x1[], const rvec x2[],
-                             real ftol, real abstol)
-{
-    int    i, m;
-    double rms;
-
-    /* For a vector you are usally not interested in a relative difference
-     * on a component that is very small compared to the other components.
-     * Therefore we do the relative comparision relative to the RMS component.
-     */
-    rms = 0.0;
-    for (i = 0; (i < n); i++)
-    {
-        for (m = 0; m < DIM; m++)
-        {
-            rms += x1[i][m]*x1[i][m] + x2[i][m]*x2[i][m];
-        }
-    }
-    rms = sqrt(rms/(2*n*DIM));
-
-    /* Convert the relative tolerance into an absolute tolerance */
-    if (ftol*rms < abstol)
-    {
-        abstol = ftol*rms;
-    }
-
-    /* And now do the actual comparision */
-    for (i = 0; (i < n); i++)
-    {
-        cmp_rvec(fp, title, i, x1[i], x2[i], 0.0, abstol);
-    }
-}
-
-static void cmp_rvecs(FILE *fp, const char *title, int n, const rvec x1[], const rvec x2[],
-                      gmx_bool bRMSD, real ftol, real abstol)
-{
-    int    i, m;
-    double d, ssd;
-
-    if (bRMSD)
-    {
-        ssd = 0;
-        for (i = 0; (i < n); i++)
-        {
-            for (m = 0; m < DIM; m++)
-            {
-                d    = x1[i][m] - x2[i][m];
-                ssd += d*d;
-            }
-        }
-        fprintf(fp, "%s RMSD %g\n", title, std::sqrt(ssd/n));
-    }
-    else
-    {
-        cmp_rvecs_rmstol(fp, title, n, x1, x2, ftol, abstol);
-    }
-}
-
-static void cmp_grpopts(FILE *fp, const t_grpopts *opt1, const t_grpopts *opt2, real ftol, real abstol)
-{
-    int  i, j;
-    char buf1[256], buf2[256];
-
-    cmp_int(fp, "inputrec->grpopts.ngtc", -1,  opt1->ngtc, opt2->ngtc);
-    cmp_int(fp, "inputrec->grpopts.ngacc", -1, opt1->ngacc, opt2->ngacc);
-    cmp_int(fp, "inputrec->grpopts.ngfrz", -1, opt1->ngfrz, opt2->ngfrz);
-    cmp_int(fp, "inputrec->grpopts.ngener", -1, opt1->ngener, opt2->ngener);
-    for (i = 0; (i < std::min(opt1->ngtc, opt2->ngtc)); i++)
-    {
-        cmp_real(fp, "inputrec->grpopts.nrdf", i, opt1->nrdf[i], opt2->nrdf[i], ftol, abstol);
-        cmp_real(fp, "inputrec->grpopts.ref_t", i, opt1->ref_t[i], opt2->ref_t[i], ftol, abstol);
-        cmp_real(fp, "inputrec->grpopts.tau_t", i, opt1->tau_t[i], opt2->tau_t[i], ftol, abstol);
-        cmp_int(fp, "inputrec->grpopts.annealing", i, opt1->annealing[i], opt2->annealing[i]);
-        cmp_int(fp, "inputrec->grpopts.anneal_npoints", i,
-                opt1->anneal_npoints[i], opt2->anneal_npoints[i]);
-        if (opt1->anneal_npoints[i] == opt2->anneal_npoints[i])
-        {
-            sprintf(buf1, "inputrec->grpopts.anneal_time[%d]", i);
-            sprintf(buf2, "inputrec->grpopts.anneal_temp[%d]", i);
-            for (j = 0; j < opt1->anneal_npoints[i]; j++)
-            {
-                cmp_real(fp, buf1, j, opt1->anneal_time[i][j], opt2->anneal_time[i][j], ftol, abstol);
-                cmp_real(fp, buf2, j, opt1->anneal_temp[i][j], opt2->anneal_temp[i][j], ftol, abstol);
-            }
-        }
-    }
-    if (opt1->ngener == opt2->ngener)
-    {
-        for (i = 0; i < opt1->ngener; i++)
-        {
-            for (j = i; j < opt1->ngener; j++)
-            {
-                sprintf(buf1, "inputrec->grpopts.egp_flags[%d]", i);
-                cmp_int(fp, buf1, j,
-                        opt1->egp_flags[opt1->ngener*i+j],
-                        opt2->egp_flags[opt1->ngener*i+j]);
-            }
-        }
-    }
-    for (i = 0; (i < std::min(opt1->ngacc, opt2->ngacc)); i++)
-    {
-        cmp_rvec(fp, "inputrec->grpopts.acc", i, opt1->acc[i], opt2->acc[i], ftol, abstol);
-    }
-    for (i = 0; (i < std::min(opt1->ngfrz, opt2->ngfrz)); i++)
-    {
-        cmp_ivec(fp, "inputrec->grpopts.nFreeze", i, opt1->nFreeze[i], opt2->nFreeze[i]);
-    }
-}
-
-static void cmp_cosines(FILE *fp, const char *s, const t_cosines c1[DIM], const t_cosines c2[DIM], real ftol, real abstol)
-{
-    int  i, m;
-    char buf[256];
-
-    for (m = 0; (m < DIM); m++)
-    {
-        sprintf(buf, "inputrec->%s[%d]", s, m);
-        cmp_int(fp, buf, 0, c1->n, c2->n);
-        for (i = 0; (i < std::min(c1->n, c2->n)); i++)
-        {
-            cmp_real(fp, buf, i, c1->a[i], c2->a[i], ftol, abstol);
-            cmp_real(fp, buf, i, c1->phi[i], c2->phi[i], ftol, abstol);
-        }
-    }
-}
-static void cmp_pull(FILE *fp)
-{
-    fprintf(fp, "WARNING: Both files use COM pulling, but comparing of the pull struct is not implemented (yet). The pull parameters could be the same or different.\n");
-}
-
-static void cmp_simtempvals(FILE *fp, const t_simtemp *simtemp1, const t_simtemp *simtemp2, int n_lambda, real ftol, real abstol)
-{
-    int i;
-    cmp_int(fp, "inputrec->simtempvals->eSimTempScale", -1, simtemp1->eSimTempScale, simtemp2->eSimTempScale);
-    cmp_real(fp, "inputrec->simtempvals->simtemp_high", -1, simtemp1->simtemp_high, simtemp2->simtemp_high, ftol, abstol);
-    cmp_real(fp, "inputrec->simtempvals->simtemp_low", -1, simtemp1->simtemp_low, simtemp2->simtemp_low, ftol, abstol);
-    for (i = 0; i < n_lambda; i++)
-    {
-        cmp_real(fp, "inputrec->simtempvals->temperatures", -1, simtemp1->temperatures[i], simtemp2->temperatures[i], ftol, abstol);
-    }
-}
-
-static void cmp_expandedvals(FILE *fp, const t_expanded *expand1, const t_expanded *expand2, int n_lambda, real ftol, real abstol)
-{
-    int i;
-
-    cmp_bool(fp, "inputrec->fepvals->bInit_weights", -1, expand1->bInit_weights, expand2->bInit_weights);
-    cmp_bool(fp, "inputrec->fepvals->bWLoneovert", -1, expand1->bWLoneovert, expand2->bWLoneovert);
-
-    for (i = 0; i < n_lambda; i++)
-    {
-        cmp_real(fp, "inputrec->expandedvals->init_lambda_weights", -1,
-                 expand1->init_lambda_weights[i], expand2->init_lambda_weights[i], ftol, abstol);
-    }
-
-    cmp_int(fp, "inputrec->expandedvals->lambda-stats", -1, expand1->elamstats, expand2->elamstats);
-    cmp_int(fp, "inputrec->expandedvals->lambda-mc-move", -1, expand1->elmcmove, expand2->elmcmove);
-    cmp_int(fp, "inputrec->expandedvals->lmc-repeats", -1, expand1->lmc_repeats, expand2->lmc_repeats);
-    cmp_int(fp, "inputrec->expandedvals->lmc-gibbsdelta", -1, expand1->gibbsdeltalam, expand2->gibbsdeltalam);
-    cmp_int(fp, "inputrec->expandedvals->lmc-forced-nstart", -1, expand1->lmc_forced_nstart, expand2->lmc_forced_nstart);
-    cmp_int(fp, "inputrec->expandedvals->lambda-weights-equil", -1, expand1->elmceq, expand2->elmceq);
-    cmp_int(fp, "inputrec->expandedvals->,weight-equil-number-all-lambda", -1, expand1->equil_n_at_lam, expand2->equil_n_at_lam);
-    cmp_int(fp, "inputrec->expandedvals->weight-equil-number-samples", -1, expand1->equil_samples, expand2->equil_samples);
-    cmp_int(fp, "inputrec->expandedvals->weight-equil-number-steps", -1, expand1->equil_steps, expand2->equil_steps);
-    cmp_real(fp, "inputrec->expandedvals->weight-equil-wl-delta", -1, expand1->equil_wl_delta, expand2->equil_wl_delta, ftol, abstol);
-    cmp_real(fp, "inputrec->expandedvals->weight-equil-count-ratio", -1, expand1->equil_ratio, expand2->equil_ratio, ftol, abstol);
-    cmp_bool(fp, "inputrec->expandedvals->symmetrized-transition-matrix", -1, expand1->bSymmetrizedTMatrix, expand2->bSymmetrizedTMatrix);
-    cmp_int(fp, "inputrec->expandedvals->nstTij", -1, expand1->nstTij, expand2->nstTij);
-    cmp_int(fp, "inputrec->expandedvals->mininum-var-min", -1, expand1->minvarmin, expand2->minvarmin); /*default is reasonable */
-    cmp_int(fp, "inputrec->expandedvals->weight-c-range", -1, expand1->c_range, expand2->c_range);      /* default is just C=0 */
-    cmp_real(fp, "inputrec->expandedvals->wl-scale", -1, expand1->wl_scale, expand2->wl_scale, ftol, abstol);
-    cmp_real(fp, "inputrec->expandedvals->init-wl-delta", -1, expand1->init_wl_delta, expand2->init_wl_delta, ftol, abstol);
-    cmp_real(fp, "inputrec->expandedvals->wl-ratio", -1, expand1->wl_ratio, expand2->wl_ratio, ftol, abstol);
-    cmp_int(fp, "inputrec->expandedvals->nstexpanded", -1, expand1->nstexpanded, expand2->nstexpanded);
-    cmp_int(fp, "inputrec->expandedvals->lmc-seed", -1, expand1->lmc_seed, expand2->lmc_seed);
-    cmp_real(fp, "inputrec->expandedvals->mc-temperature", -1, expand1->mc_temp, expand2->mc_temp, ftol, abstol);
-}
-
-static void cmp_fepvals(FILE *fp, const t_lambda *fep1, const t_lambda *fep2, real ftol, real abstol)
-{
-    int i, j;
-    cmp_int(fp, "inputrec->nstdhdl", -1, fep1->nstdhdl, fep2->nstdhdl);
-    cmp_double(fp, "inputrec->fepvals->init_fep_state", -1, fep1->init_fep_state, fep2->init_fep_state, ftol, abstol);
-    cmp_double(fp, "inputrec->fepvals->delta_lambda", -1, fep1->delta_lambda, fep2->delta_lambda, ftol, abstol);
-    cmp_int(fp, "inputrec->fepvals->n_lambda", -1, fep1->n_lambda, fep2->n_lambda);
-    for (i = 0; i < efptNR; i++)
-    {
-        for (j = 0; j < std::min(fep1->n_lambda, fep2->n_lambda); j++)
-        {
-            cmp_double(fp, "inputrec->fepvals->all_lambda", -1, fep1->all_lambda[i][j], fep2->all_lambda[i][j], ftol, abstol);
-        }
-    }
-    cmp_int(fp, "inputrec->fepvals->lambda_neighbors", 1, fep1->lambda_neighbors,
-            fep2->lambda_neighbors);
-    cmp_real(fp, "inputrec->fepvals->sc_alpha", -1, fep1->sc_alpha, fep2->sc_alpha, ftol, abstol);
-    cmp_int(fp, "inputrec->fepvals->sc_power", -1, fep1->sc_power, fep2->sc_power);
-    cmp_real(fp, "inputrec->fepvals->sc_r_power", -1, fep1->sc_r_power, fep2->sc_r_power, ftol, abstol);
-    cmp_real(fp, "inputrec->fepvals->sc_sigma", -1, fep1->sc_sigma, fep2->sc_sigma, ftol, abstol);
-    cmp_int(fp, "inputrec->fepvals->edHdLPrintEnergy", -1, fep1->edHdLPrintEnergy, fep1->edHdLPrintEnergy);
-    cmp_bool(fp, "inputrec->fepvals->bScCoul", -1, fep1->bScCoul, fep1->bScCoul);
-    cmp_int(fp, "inputrec->separate_dhdl_file", -1, fep1->separate_dhdl_file, fep2->separate_dhdl_file);
-    cmp_int(fp, "inputrec->dhdl_derivatives", -1, fep1->dhdl_derivatives, fep2->dhdl_derivatives);
-    cmp_int(fp, "inputrec->dh_hist_size", -1, fep1->dh_hist_size, fep2->dh_hist_size);
-    cmp_double(fp, "inputrec->dh_hist_spacing", -1, fep1->dh_hist_spacing, fep2->dh_hist_spacing, ftol, abstol);
-}
-
-static void cmp_inputrec(FILE *fp, const t_inputrec *ir1, const t_inputrec *ir2, real ftol, real abstol)
-{
-    fprintf(fp, "comparing inputrec\n");
-
-    /* gcc 2.96 doesnt like these defines at all, but issues a huge list
-     * of warnings. Maybe it will change in future versions, but for the
-     * moment I've spelled them out instead. /EL 000820
-     * #define CIB(s) cmp_int(fp,"inputrec->"#s,0,ir1->##s,ir2->##s)
-     * #define CII(s) cmp_int(fp,"inputrec->"#s,0,ir1->##s,ir2->##s)
-     * #define CIR(s) cmp_real(fp,"inputrec->"#s,0,ir1->##s,ir2->##s,ftol)
-     */
-    cmp_int(fp, "inputrec->eI", -1, ir1->eI, ir2->eI);
-    cmp_int64(fp, "inputrec->nsteps", ir1->nsteps, ir2->nsteps);
-    cmp_int64(fp, "inputrec->init_step", ir1->init_step, ir2->init_step);
-    cmp_int(fp, "inputrec->simulation_part", -1, ir1->simulation_part, ir2->simulation_part);
-    cmp_int(fp, "inputrec->ePBC", -1, ir1->ePBC, ir2->ePBC);
-    cmp_int(fp, "inputrec->bPeriodicMols", -1, ir1->bPeriodicMols, ir2->bPeriodicMols);
-    cmp_int(fp, "inputrec->cutoff_scheme", -1, ir1->cutoff_scheme, ir2->cutoff_scheme);
-    cmp_int(fp, "inputrec->ns_type", -1, ir1->ns_type, ir2->ns_type);
-    cmp_int(fp, "inputrec->nstlist", -1, ir1->nstlist, ir2->nstlist);
-    cmp_int(fp, "inputrec->nstcomm", -1, ir1->nstcomm, ir2->nstcomm);
-    cmp_int(fp, "inputrec->comm_mode", -1, ir1->comm_mode, ir2->comm_mode);
-    cmp_int(fp, "inputrec->nstlog", -1, ir1->nstlog, ir2->nstlog);
-    cmp_int(fp, "inputrec->nstxout", -1, ir1->nstxout, ir2->nstxout);
-    cmp_int(fp, "inputrec->nstvout", -1, ir1->nstvout, ir2->nstvout);
-    cmp_int(fp, "inputrec->nstfout", -1, ir1->nstfout, ir2->nstfout);
-    cmp_int(fp, "inputrec->nstcalcenergy", -1, ir1->nstcalcenergy, ir2->nstcalcenergy);
-    cmp_int(fp, "inputrec->nstenergy", -1, ir1->nstenergy, ir2->nstenergy);
-    cmp_int(fp, "inputrec->nstxout_compressed", -1, ir1->nstxout_compressed, ir2->nstxout_compressed);
-    cmp_double(fp, "inputrec->init_t", -1, ir1->init_t, ir2->init_t, ftol, abstol);
-    cmp_double(fp, "inputrec->delta_t", -1, ir1->delta_t, ir2->delta_t, ftol, abstol);
-    cmp_real(fp, "inputrec->x_compression_precision", -1, ir1->x_compression_precision, ir2->x_compression_precision, ftol, abstol);
-    cmp_real(fp, "inputrec->fourierspacing", -1, ir1->fourier_spacing, ir2->fourier_spacing, ftol, abstol);
-    cmp_int(fp, "inputrec->nkx", -1, ir1->nkx, ir2->nkx);
-    cmp_int(fp, "inputrec->nky", -1, ir1->nky, ir2->nky);
-    cmp_int(fp, "inputrec->nkz", -1, ir1->nkz, ir2->nkz);
-    cmp_int(fp, "inputrec->pme_order", -1, ir1->pme_order, ir2->pme_order);
-    cmp_real(fp, "inputrec->ewald_rtol", -1, ir1->ewald_rtol, ir2->ewald_rtol, ftol, abstol);
-    cmp_int(fp, "inputrec->ewald_geometry", -1, ir1->ewald_geometry, ir2->ewald_geometry);
-    cmp_real(fp, "inputrec->epsilon_surface", -1, ir1->epsilon_surface, ir2->epsilon_surface, ftol, abstol);
-    cmp_int(fp, "inputrec->bContinuation", -1, ir1->bContinuation, ir2->bContinuation);
-    cmp_int(fp, "inputrec->bShakeSOR", -1, ir1->bShakeSOR, ir2->bShakeSOR);
-    cmp_int(fp, "inputrec->etc", -1, ir1->etc, ir2->etc);
-    cmp_int(fp, "inputrec->bPrintNHChains", -1, ir1->bPrintNHChains, ir2->bPrintNHChains);
-    cmp_int(fp, "inputrec->epc", -1, ir1->epc, ir2->epc);
-    cmp_int(fp, "inputrec->epct", -1, ir1->epct, ir2->epct);
-    cmp_real(fp, "inputrec->tau_p", -1, ir1->tau_p, ir2->tau_p, ftol, abstol);
-    cmp_rvec(fp, "inputrec->ref_p(x)", -1, ir1->ref_p[XX], ir2->ref_p[XX], ftol, abstol);
-    cmp_rvec(fp, "inputrec->ref_p(y)", -1, ir1->ref_p[YY], ir2->ref_p[YY], ftol, abstol);
-    cmp_rvec(fp, "inputrec->ref_p(z)", -1, ir1->ref_p[ZZ], ir2->ref_p[ZZ], ftol, abstol);
-    cmp_rvec(fp, "inputrec->compress(x)", -1, ir1->compress[XX], ir2->compress[XX], ftol, abstol);
-    cmp_rvec(fp, "inputrec->compress(y)", -1, ir1->compress[YY], ir2->compress[YY], ftol, abstol);
-    cmp_rvec(fp, "inputrec->compress(z)", -1, ir1->compress[ZZ], ir2->compress[ZZ], ftol, abstol);
-    cmp_int(fp, "refcoord_scaling", -1, ir1->refcoord_scaling, ir2->refcoord_scaling);
-    cmp_rvec(fp, "inputrec->posres_com", -1, ir1->posres_com, ir2->posres_com, ftol, abstol);
-    cmp_rvec(fp, "inputrec->posres_comB", -1, ir1->posres_comB, ir2->posres_comB, ftol, abstol);
-    cmp_real(fp, "inputrec->verletbuf_tol", -1, ir1->verletbuf_tol, ir2->verletbuf_tol, ftol, abstol);
-    cmp_real(fp, "inputrec->rlist", -1, ir1->rlist, ir2->rlist, ftol, abstol);
-    cmp_real(fp, "inputrec->rtpi", -1, ir1->rtpi, ir2->rtpi, ftol, abstol);
-    cmp_int(fp, "inputrec->coulombtype", -1, ir1->coulombtype, ir2->coulombtype);
-    cmp_int(fp, "inputrec->coulomb_modifier", -1, ir1->coulomb_modifier, ir2->coulomb_modifier);
-    cmp_real(fp, "inputrec->rcoulomb_switch", -1, ir1->rcoulomb_switch, ir2->rcoulomb_switch, ftol, abstol);
-    cmp_real(fp, "inputrec->rcoulomb", -1, ir1->rcoulomb, ir2->rcoulomb, ftol, abstol);
-    cmp_int(fp, "inputrec->vdwtype", -1, ir1->vdwtype, ir2->vdwtype);
-    cmp_int(fp, "inputrec->vdw_modifier", -1, ir1->vdw_modifier, ir2->vdw_modifier);  cmp_real(fp, "inputrec->rvdw_switch", -1, ir1->rvdw_switch, ir2->rvdw_switch, ftol, abstol);
-    cmp_real(fp, "inputrec->rvdw", -1, ir1->rvdw, ir2->rvdw, ftol, abstol);
-    cmp_real(fp, "inputrec->epsilon_r", -1, ir1->epsilon_r, ir2->epsilon_r, ftol, abstol);
-    cmp_real(fp, "inputrec->epsilon_rf", -1, ir1->epsilon_rf, ir2->epsilon_rf, ftol, abstol);
-    cmp_real(fp, "inputrec->tabext", -1, ir1->tabext, ir2->tabext, ftol, abstol);
-    cmp_int(fp, "inputrec->implicit_solvent", -1, ir1->implicit_solvent, ir2->implicit_solvent);
-    cmp_int(fp, "inputrec->gb_algorithm", -1, ir1->gb_algorithm, ir2->gb_algorithm);
-    cmp_int(fp, "inputrec->nstgbradii", -1, ir1->nstgbradii, ir2->nstgbradii);
-    cmp_real(fp, "inputrec->rgbradii", -1, ir1->rgbradii, ir2->rgbradii, ftol, abstol);
-    cmp_real(fp, "inputrec->gb_saltconc", -1, ir1->gb_saltconc, ir2->gb_saltconc, ftol, abstol);
-    cmp_real(fp, "inputrec->gb_epsilon_solvent", -1, ir1->gb_epsilon_solvent, ir2->gb_epsilon_solvent, ftol, abstol);
-    cmp_real(fp, "inputrec->gb_obc_alpha", -1, ir1->gb_obc_alpha, ir2->gb_obc_alpha, ftol, abstol);
-    cmp_real(fp, "inputrec->gb_obc_beta", -1, ir1->gb_obc_beta, ir2->gb_obc_beta, ftol, abstol);
-    cmp_real(fp, "inputrec->gb_obc_gamma", -1, ir1->gb_obc_gamma, ir2->gb_obc_gamma, ftol, abstol);
-    cmp_real(fp, "inputrec->gb_dielectric_offset", -1, ir1->gb_dielectric_offset, ir2->gb_dielectric_offset, ftol, abstol);
-    cmp_int(fp, "inputrec->sa_algorithm", -1, ir1->sa_algorithm, ir2->sa_algorithm);
-    cmp_real(fp, "inputrec->sa_surface_tension", -1, ir1->sa_surface_tension, ir2->sa_surface_tension, ftol, abstol);
-
-    cmp_int(fp, "inputrec->eDispCorr", -1, ir1->eDispCorr, ir2->eDispCorr);
-    cmp_real(fp, "inputrec->shake_tol", -1, ir1->shake_tol, ir2->shake_tol, ftol, abstol);
-    cmp_int(fp, "inputrec->efep", -1, ir1->efep, ir2->efep);
-    cmp_fepvals(fp, ir1->fepvals, ir2->fepvals, ftol, abstol);
-    cmp_int(fp, "inputrec->bSimTemp", -1, ir1->bSimTemp, ir2->bSimTemp);
-    if ((ir1->bSimTemp == ir2->bSimTemp) && (ir1->bSimTemp))
-    {
-        cmp_simtempvals(fp, ir1->simtempvals, ir2->simtempvals, std::min(ir1->fepvals->n_lambda, ir2->fepvals->n_lambda), ftol, abstol);
-    }
-    cmp_int(fp, "inputrec->bExpanded", -1, ir1->bExpanded, ir2->bExpanded);
-    if ((ir1->bExpanded == ir2->bExpanded) && (ir1->bExpanded))
-    {
-        cmp_expandedvals(fp, ir1->expandedvals, ir2->expandedvals, std::min(ir1->fepvals->n_lambda, ir2->fepvals->n_lambda), ftol, abstol);
-    }
-    cmp_int(fp, "inputrec->nwall", -1, ir1->nwall, ir2->nwall);
-    cmp_int(fp, "inputrec->wall_type", -1, ir1->wall_type, ir2->wall_type);
-    cmp_int(fp, "inputrec->wall_atomtype[0]", -1, ir1->wall_atomtype[0], ir2->wall_atomtype[0]);
-    cmp_int(fp, "inputrec->wall_atomtype[1]", -1, ir1->wall_atomtype[1], ir2->wall_atomtype[1]);
-    cmp_real(fp, "inputrec->wall_density[0]", -1, ir1->wall_density[0], ir2->wall_density[0], ftol, abstol);
-    cmp_real(fp, "inputrec->wall_density[1]", -1, ir1->wall_density[1], ir2->wall_density[1], ftol, abstol);
-    cmp_real(fp, "inputrec->wall_ewald_zfac", -1, ir1->wall_ewald_zfac, ir2->wall_ewald_zfac, ftol, abstol);
-
-    cmp_bool(fp, "inputrec->bPull", -1, ir1->bPull, ir2->bPull);
-    if (ir1->bPull && ir2->bPull)
-    {
-        cmp_pull(fp);
-    }
-
-    cmp_int(fp, "inputrec->eDisre", -1, ir1->eDisre, ir2->eDisre);
-    cmp_real(fp, "inputrec->dr_fc", -1, ir1->dr_fc, ir2->dr_fc, ftol, abstol);
-    cmp_int(fp, "inputrec->eDisreWeighting", -1, ir1->eDisreWeighting, ir2->eDisreWeighting);
-    cmp_int(fp, "inputrec->bDisreMixed", -1, ir1->bDisreMixed, ir2->bDisreMixed);
-    cmp_int(fp, "inputrec->nstdisreout", -1, ir1->nstdisreout, ir2->nstdisreout);
-    cmp_real(fp, "inputrec->dr_tau", -1, ir1->dr_tau, ir2->dr_tau, ftol, abstol);
-    cmp_real(fp, "inputrec->orires_fc", -1, ir1->orires_fc, ir2->orires_fc, ftol, abstol);
-    cmp_real(fp, "inputrec->orires_tau", -1, ir1->orires_tau, ir2->orires_tau, ftol, abstol);
-    cmp_int(fp, "inputrec->nstorireout", -1, ir1->nstorireout, ir2->nstorireout);
-    cmp_real(fp, "inputrec->em_stepsize", -1, ir1->em_stepsize, ir2->em_stepsize, ftol, abstol);
-    cmp_real(fp, "inputrec->em_tol", -1, ir1->em_tol, ir2->em_tol, ftol, abstol);
-    cmp_int(fp, "inputrec->niter", -1, ir1->niter, ir2->niter);
-    cmp_real(fp, "inputrec->fc_stepsize", -1, ir1->fc_stepsize, ir2->fc_stepsize, ftol, abstol);
-    cmp_int(fp, "inputrec->nstcgsteep", -1, ir1->nstcgsteep, ir2->nstcgsteep);
-    cmp_int(fp, "inputrec->nbfgscorr", 0, ir1->nbfgscorr, ir2->nbfgscorr);
-    cmp_int(fp, "inputrec->eConstrAlg", -1, ir1->eConstrAlg, ir2->eConstrAlg);
-    cmp_int(fp, "inputrec->nProjOrder", -1, ir1->nProjOrder, ir2->nProjOrder);
-    cmp_real(fp, "inputrec->LincsWarnAngle", -1, ir1->LincsWarnAngle, ir2->LincsWarnAngle, ftol, abstol);
-    cmp_int(fp, "inputrec->nLincsIter", -1, ir1->nLincsIter, ir2->nLincsIter);
-    cmp_real(fp, "inputrec->bd_fric", -1, ir1->bd_fric, ir2->bd_fric, ftol, abstol);
-    cmp_int64(fp, "inputrec->ld_seed", ir1->ld_seed, ir2->ld_seed);
-    cmp_real(fp, "inputrec->cos_accel", -1, ir1->cos_accel, ir2->cos_accel, ftol, abstol);
-    cmp_rvec(fp, "inputrec->deform(a)", -1, ir1->deform[XX], ir2->deform[XX], ftol, abstol);
-    cmp_rvec(fp, "inputrec->deform(b)", -1, ir1->deform[YY], ir2->deform[YY], ftol, abstol);
-    cmp_rvec(fp, "inputrec->deform(c)", -1, ir1->deform[ZZ], ir2->deform[ZZ], ftol, abstol);
-
-
-    cmp_int(fp, "inputrec->userint1", -1, ir1->userint1, ir2->userint1);
-    cmp_int(fp, "inputrec->userint2", -1, ir1->userint2, ir2->userint2);
-    cmp_int(fp, "inputrec->userint3", -1, ir1->userint3, ir2->userint3);
-    cmp_int(fp, "inputrec->userint4", -1, ir1->userint4, ir2->userint4);
-    cmp_real(fp, "inputrec->userreal1", -1, ir1->userreal1, ir2->userreal1, ftol, abstol);
-    cmp_real(fp, "inputrec->userreal2", -1, ir1->userreal2, ir2->userreal2, ftol, abstol);
-    cmp_real(fp, "inputrec->userreal3", -1, ir1->userreal3, ir2->userreal3, ftol, abstol);
-    cmp_real(fp, "inputrec->userreal4", -1, ir1->userreal4, ir2->userreal4, ftol, abstol);
-    cmp_grpopts(fp, &(ir1->opts), &(ir2->opts), ftol, abstol);
-    cmp_cosines(fp, "ex", ir1->ex, ir2->ex, ftol, abstol);
-    cmp_cosines(fp, "et", ir1->et, ir2->et, ftol, abstol);
-}
-
-static void comp_pull_AB(FILE *fp, pull_params_t *pull, real ftol, real abstol)
-{
-    int i;
-
-    for (i = 0; i < pull->ncoord; i++)
-    {
-        fprintf(fp, "comparing pull coord %d\n", i);
-        cmp_real(fp, "pull-coord->k", -1, pull->coord[i].k, pull->coord[i].kB, ftol, abstol);
-    }
-}
-
-static void comp_state(const t_state *st1, const t_state *st2,
-                       gmx_bool bRMSD, real ftol, real abstol)
-{
-    int i, j, nc;
-
-    fprintf(stdout, "comparing flags\n");
-    cmp_int(stdout, "flags", -1, st1->flags, st2->flags);
-    fprintf(stdout, "comparing box\n");
-    cmp_rvecs(stdout, "box", DIM, st1->box, st2->box, FALSE, ftol, abstol);
-    fprintf(stdout, "comparing box_rel\n");
-    cmp_rvecs(stdout, "box_rel", DIM, st1->box_rel, st2->box_rel, FALSE, ftol, abstol);
-    fprintf(stdout, "comparing boxv\n");
-    cmp_rvecs(stdout, "boxv", DIM, st1->boxv, st2->boxv, FALSE, ftol, abstol);
-    if (st1->flags & (1<<estSVIR_PREV))
-    {
-        fprintf(stdout, "comparing shake vir_prev\n");
-        cmp_rvecs(stdout, "svir_prev", DIM, st1->svir_prev, st2->svir_prev, FALSE, ftol, abstol);
-    }
-    if (st1->flags & (1<<estFVIR_PREV))
-    {
-        fprintf(stdout, "comparing force vir_prev\n");
-        cmp_rvecs(stdout, "fvir_prev", DIM, st1->fvir_prev, st2->fvir_prev, FALSE, ftol, abstol);
-    }
-    if (st1->flags & (1<<estPRES_PREV))
-    {
-        fprintf(stdout, "comparing prev_pres\n");
-        cmp_rvecs(stdout, "pres_prev", DIM, st1->pres_prev, st2->pres_prev, FALSE, ftol, abstol);
-    }
-    cmp_int(stdout, "ngtc", -1, st1->ngtc, st2->ngtc);
-    cmp_int(stdout, "nhchainlength", -1, st1->nhchainlength, st2->nhchainlength);
-    if (st1->ngtc == st2->ngtc && st1->nhchainlength == st2->nhchainlength)
-    {
-        for (i = 0; i < st1->ngtc; i++)
-        {
-            nc = i*st1->nhchainlength;
-            for (j = 0; j < nc; j++)
-            {
-                cmp_real(stdout, "nosehoover_xi",
-                         i, st1->nosehoover_xi[nc+j], st2->nosehoover_xi[nc+j], ftol, abstol);
-            }
-        }
-    }
-    cmp_int(stdout, "nnhpres", -1, st1->nnhpres, st2->nnhpres);
-    if (st1->nnhpres == st2->nnhpres && st1->nhchainlength == st2->nhchainlength)
-    {
-        for (i = 0; i < st1->nnhpres; i++)
-        {
-            nc = i*st1->nhchainlength;
-            for (j = 0; j < nc; j++)
-            {
-                cmp_real(stdout, "nosehoover_xi",
-                         i, st1->nhpres_xi[nc+j], st2->nhpres_xi[nc+j], ftol, abstol);
-            }
-        }
-    }
-
-    cmp_int(stdout, "natoms", -1, st1->natoms, st2->natoms);
-    if (st1->natoms == st2->natoms)
-    {
-        if ((st1->flags & (1<<estX)) && (st2->flags & (1<<estX)))
-        {
-            fprintf(stdout, "comparing x\n");
-            cmp_rvecs(stdout, "x", st1->natoms, st1->x, st2->x, bRMSD, ftol, abstol);
-        }
-        if ((st1->flags & (1<<estV)) && (st2->flags & (1<<estV)))
-        {
-            fprintf(stdout, "comparing v\n");
-            cmp_rvecs(stdout, "v", st1->natoms, st1->v, st2->v, bRMSD, ftol, abstol);
-        }
-    }
-}
-
-void comp_tpx(const char *fn1, const char *fn2,
-              gmx_bool bRMSD, real ftol, real abstol)
-{
-    const char  *ff[2];
-    t_inputrec   ir[2];
-    t_state      state[2];
-    gmx_mtop_t   mtop[2];
-    t_topology   top[2];
-    int          i;
-
-    ff[0] = fn1;
-    ff[1] = fn2;
-    for (i = 0; i < (fn2 ? 2 : 1); i++)
-    {
-        read_tpx_state(ff[i], &(ir[i]), &state[i], &(mtop[i]));
-    }
-    if (fn2)
-    {
-        cmp_inputrec(stdout, &ir[0], &ir[1], ftol, abstol);
-        /* Convert gmx_mtop_t to t_topology.
-         * We should implement direct mtop comparison,
-         * but it might be useful to keep t_topology comparison as an option.
-         */
-        top[0] = gmx_mtop_t_to_t_topology(&mtop[0]);
-        top[1] = gmx_mtop_t_to_t_topology(&mtop[1]);
-        cmp_top(stdout, &top[0], &top[1], ftol, abstol);
-        cmp_groups(stdout, &mtop[0].groups, &mtop[1].groups,
-                   mtop[0].natoms, mtop[1].natoms);
-        comp_state(&state[0], &state[1], bRMSD, ftol, abstol);
-    }
-    else
-    {
-        if (ir[0].efep == efepNO)
-        {
-            fprintf(stdout, "inputrec->efep = %s\n", efep_names[ir[0].efep]);
-        }
-        else
-        {
-            if (ir[0].bPull)
-            {
-                comp_pull_AB(stdout, ir->pull, ftol, abstol);
-            }
-            /* Convert gmx_mtop_t to t_topology.
-             * We should implement direct mtop comparison,
-             * but it might be useful to keep t_topology comparison as an option.
-             */
-            top[0] = gmx_mtop_t_to_t_topology(&mtop[0]);
-            cmp_top(stdout, &top[0], NULL, ftol, abstol);
-        }
-    }
-}
-
-void comp_frame(FILE *fp, t_trxframe *fr1, t_trxframe *fr2,
-                gmx_bool bRMSD, real ftol, real abstol)
-{
-    fprintf(fp, "\n");
-    cmp_int(fp, "not_ok", -1, fr1->not_ok, fr2->not_ok);
-    cmp_int(fp, "natoms", -1, fr1->natoms, fr2->natoms);
-    if (cmp_bool(fp, "bTitle", -1, fr1->bTitle, fr2->bTitle))
-    {
-        cmp_str(fp, "title", -1, fr1->title, fr2->title);
-    }
-    if (cmp_bool(fp, "bStep", -1, fr1->bStep, fr2->bStep))
-    {
-        cmp_int(fp, "step", -1, fr1->step, fr2->step);
-    }
-    cmp_int(fp, "step", -1, fr1->step, fr2->step);
-    if (cmp_bool(fp, "bTime", -1, fr1->bTime, fr2->bTime))
-    {
-        cmp_real(fp, "time", -1, fr1->time, fr2->time, ftol, abstol);
-    }
-    if (cmp_bool(fp, "bLambda", -1, fr1->bLambda, fr2->bLambda))
-    {
-        cmp_real(fp, "lambda", -1, fr1->lambda, fr2->lambda, ftol, abstol);
-    }
-    if (cmp_bool(fp, "bAtoms", -1, fr1->bAtoms, fr2->bAtoms))
-    {
-        cmp_atoms(fp, fr1->atoms, fr2->atoms, ftol, abstol);
-    }
-    if (cmp_bool(fp, "bPrec", -1, fr1->bPrec, fr2->bPrec))
-    {
-        cmp_real(fp, "prec", -1, fr1->prec, fr2->prec, ftol, abstol);
-    }
-    if (cmp_bool(fp, "bX", -1, fr1->bX, fr2->bX))
-    {
-        cmp_rvecs(fp, "x", std::min(fr1->natoms, fr2->natoms), fr1->x, fr2->x, bRMSD, ftol, abstol);
-    }
-    if (cmp_bool(fp, "bV", -1, fr1->bV, fr2->bV))
-    {
-        cmp_rvecs(fp, "v", std::min(fr1->natoms, fr2->natoms), fr1->v, fr2->v, bRMSD, ftol, abstol);
-    }
-    if (cmp_bool(fp, "bF", -1, fr1->bF, fr2->bF))
-    {
-        cmp_rvecs(fp, "f", std::min(fr1->natoms, fr2->natoms), fr1->f, fr2->f, bRMSD, ftol, abstol);
-    }
-    if (cmp_bool(fp, "bBox", -1, fr1->bBox, fr2->bBox))
-    {
-        cmp_rvecs(fp, "box", 3, fr1->box, fr2->box, FALSE, ftol, abstol);
-    }
-}
-
-void comp_trx(const gmx_output_env_t *oenv, const char *fn1, const char *fn2,
-              gmx_bool bRMSD, real ftol, real abstol)
-{
-    int          i;
-    const char  *fn[2];
-    t_trxframe   fr[2];
-    t_trxstatus *status[2];
-    gmx_bool     b[2];
-
-    fn[0] = fn1;
-    fn[1] = fn2;
-    fprintf(stderr, "Comparing trajectory files %s and %s\n", fn1, fn2);
-    for (i = 0; i < 2; i++)
-    {
-        b[i] = read_first_frame(oenv, &status[i], fn[i], &fr[i], TRX_READ_X|TRX_READ_V|TRX_READ_F);
-    }
-
-    if (b[0] && b[1])
-    {
-        do
-        {
-            comp_frame(stdout, &(fr[0]), &(fr[1]), bRMSD, ftol, abstol);
-
-            for (i = 0; i < 2; i++)
-            {
-                b[i] = read_next_frame(oenv, status[i], &fr[i]);
-            }
-        }
-        while (b[0] && b[1]);
-
-        for (i = 0; i < 2; i++)
-        {
-            if (b[i] && !b[1-i])
-            {
-                fprintf(stdout, "\nEnd of file on %s but not on %s\n", fn[1-i], fn[i]);
-            }
-            close_trj(status[i]);
-        }
-    }
-    if (!b[0] && !b[1])
-    {
-        fprintf(stdout, "\nBoth files read correctly\n");
-    }
-}
-
-static real ener_tensor_diag(int n, int *ind1, int *ind2,
-                             gmx_enxnm_t *enm1,
-                             int *tensi, int i,
-                             t_energy e1[], t_energy e2[])
-{
-    int    d1, d2;
-    int    j;
-    real   prod1, prod2;
-    int    nfound;
-    size_t len;
-
-    d1 = tensi[i]/DIM;
-    d2 = tensi[i] - d1*DIM;
-
-    /* Find the diagonal elements d1 and d2 */
-    len    = std::strlen(enm1[ind1[i]].name);
-    prod1  = 1;
-    prod2  = 1;
-    nfound = 0;
-    for (j = 0; j < n; j++)
-    {
-        if (tensi[j] >= 0 &&
-            std::strlen(enm1[ind1[j]].name) == len &&
-            std::strncmp(enm1[ind1[i]].name, enm1[ind1[j]].name, len-2) == 0 &&
-            (tensi[j] == d1*DIM+d1 || tensi[j] == d2*DIM+d2))
-        {
-            prod1 *= fabs(e1[ind1[j]].e);
-            prod2 *= fabs(e2[ind2[j]].e);
-            nfound++;
-        }
-    }
-
-    if (nfound == 2)
-    {
-        return 0.5*(std::sqrt(prod1) + std::sqrt(prod2));
-    }
-    else
-    {
-        return 0;
-    }
-}
-
-static gmx_bool enernm_equal(const char *nm1, const char *nm2)
-{
-    int len1, len2;
-
-    len1 = std::strlen(nm1);
-    len2 = std::strlen(nm2);
-
-    /* Remove " (bar)" at the end of a name */
-    if (len1 > 6 && std::strcmp(nm1+len1-6, " (bar)") == 0)
-    {
-        len1 -= 6;
-    }
-    if (len2 > 6 && std::strcmp(nm2+len2-6, " (bar)") == 0)
-    {
-        len2 -= 6;
-    }
-
-    return (len1 == len2 && gmx_strncasecmp(nm1, nm2, len1) == 0);
-}
-
-static void cmp_energies(FILE *fp, int step1, int step2,
-                         t_energy e1[], t_energy e2[],
-                         gmx_enxnm_t *enm1,
-                         real ftol, real abstol,
-                         int nre, int *ind1, int *ind2, int maxener)
-{
-    int   i, ii;
-    int  *tensi, len, d1, d2;
-    real  ftol_i, abstol_i;
-
-    snew(tensi, maxener);
-    /* Check for tensor elements ending on "-XX", "-XY", ... , "-ZZ" */
-    for (i = 0; (i < maxener); i++)
-    {
-        ii       = ind1[i];
-        tensi[i] = -1;
-        len      = std::strlen(enm1[ii].name);
-        if (len > 3 && enm1[ii].name[len-3] == '-')
-        {
-            d1 = enm1[ii].name[len-2] - 'X';
-            d2 = enm1[ii].name[len-1] - 'X';
-            if (d1 >= 0 && d1 < DIM &&
-                d2 >= 0 && d2 < DIM)
-            {
-                tensi[i] = d1*DIM + d2;
-            }
-        }
-    }
-
-    for (i = 0; (i < maxener); i++)
-    {
-        /* Check if this is an off-diagonal tensor element */
-        if (tensi[i] >= 0 && tensi[i] != 0 && tensi[i] != 4 && tensi[i] != 8)
-        {
-            /* Turn on the relative tolerance check (4 is maximum relative diff.) */
-            ftol_i = 5;
-            /* Do the relative tolerance through an absolute tolerance times
-             * the size of diagonal components of the tensor.
-             */
-            abstol_i = ftol*ener_tensor_diag(nre, ind1, ind2, enm1, tensi, i, e1, e2);
-            if (debug)
-            {
-                fprintf(debug, "tensor '%s' val %f diag %f\n",
-                        enm1[i].name, e1[i].e, abstol_i/ftol);
-            }
-            if (abstol_i > 0)
-            {
-                /* We found a diagonal, we need to check with the minimum tolerance */
-                abstol_i = std::min(abstol_i, abstol);
-            }
-            else
-            {
-                /* We did not find a diagonal, ignore the relative tolerance check */
-                abstol_i = abstol;
-            }
-        }
-        else
-        {
-            ftol_i   = ftol;
-            abstol_i = abstol;
-        }
-        if (!equal_real(e1[ind1[i]].e, e2[ind2[i]].e, ftol_i, abstol_i))
-        {
-            fprintf(fp, "%-15s  step %3d:  %12g,  step %3d: %12g\n",
-                    enm1[ind1[i]].name,
-                    step1, e1[ind1[i]].e,
-                    step2, e2[ind2[i]].e);
-        }
-    }
-
-    sfree(tensi);
-}
-
-#if 0
-static void cmp_disres(t_enxframe *fr1, t_enxframe *fr2, real ftol, real abstol)
-{
-    int  i;
-    char bav[64], bt[64], bs[22];
-
-    cmp_int(stdout, "ndisre", -1, fr1->ndisre, fr2->ndisre);
-    if ((fr1->ndisre == fr2->ndisre) && (fr1->ndisre > 0))
-    {
-        sprintf(bav, "step %s: disre rav", gmx_step_str(fr1->step, bs));
-        sprintf(bt, "step %s: disre  rt", gmx_step_str(fr1->step, bs));
-        for (i = 0; (i < fr1->ndisre); i++)
-        {
-            cmp_real(stdout, bav, i, fr1->disre_rm3tav[i], fr2->disre_rm3tav[i], ftol, abstol);
-            cmp_real(stdout, bt, i, fr1->disre_rt[i], fr2->disre_rt[i], ftol, abstol);
-        }
-    }
-}
-#endif
-
-static void cmp_eblocks(t_enxframe *fr1, t_enxframe *fr2, real ftol, real abstol)
-{
-    int  i, j, k;
-    char buf[64], bs[22];
-
-    cmp_int(stdout, "nblock", -1, fr1->nblock, fr2->nblock);
-    if ((fr1->nblock == fr2->nblock) && (fr1->nblock > 0))
-    {
-        for (j = 0; (j < fr1->nblock); j++)
-        {
-            t_enxblock *b1, *b2; /* convenience vars */
-
-            b1 = &(fr1->block[j]);
-            b2 = &(fr2->block[j]);
-
-            sprintf(buf, "step %s: block[%d]", gmx_step_str(fr1->step, bs), j);
-            cmp_int(stdout, buf, -1, b1->nsub, b2->nsub);
-            cmp_int(stdout, buf, -1, b1->id, b2->id);
-
-            if ( (b1->nsub == b2->nsub) && (b1->id == b2->id) )
-            {
-                for (i = 0; i < b1->nsub; i++)
-                {
-                    t_enxsubblock *s1, *s2;
-
-                    s1 = &(b1->sub[i]);
-                    s2 = &(b2->sub[i]);
-
-                    cmp_int(stdout, buf, -1, (int)s1->type, (int)s2->type);
-                    cmp_int64(stdout, buf, s1->nr, s2->nr);
-
-                    if ((s1->type == s2->type) && (s1->nr == s2->nr))
-                    {
-                        switch (s1->type)
-                        {
-                            case xdr_datatype_float:
-                                for (k = 0; k < s1->nr; k++)
-                                {
-                                    cmp_float(stdout, buf, i,
-                                              s1->fval[k], s2->fval[k],
-                                              ftol, abstol);
-                                }
-                                break;
-                            case xdr_datatype_double:
-                                for (k = 0; k < s1->nr; k++)
-                                {
-                                    cmp_double(stdout, buf, i,
-                                               s1->dval[k], s2->dval[k],
-                                               ftol, abstol);
-                                }
-                                break;
-                            case xdr_datatype_int:
-                                for (k = 0; k < s1->nr; k++)
-                                {
-                                    cmp_int(stdout, buf, i,
-                                            s1->ival[k], s2->ival[k]);
-                                }
-                                break;
-                            case xdr_datatype_int64:
-                                for (k = 0; k < s1->nr; k++)
-                                {
-                                    cmp_int64(stdout, buf,
-                                              s1->lval[k], s2->lval[k]);
-                                }
-                                break;
-                            case xdr_datatype_char:
-                                for (k = 0; k < s1->nr; k++)
-                                {
-                                    cmp_uc(stdout, buf, i,
-                                           s1->cval[k], s2->cval[k]);
-                                }
-                                break;
-                            case xdr_datatype_string:
-                                for (k = 0; k < s1->nr; k++)
-                                {
-                                    cmp_str(stdout, buf, i,
-                                            s1->sval[k], s2->sval[k]);
-                                }
-                                break;
-                            default:
-                                gmx_incons("Unknown data type!!");
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
-
-void comp_enx(const char *fn1, const char *fn2, real ftol, real abstol, const char *lastener)
-{
-    int            nre, nre1, nre2;
-    ener_file_t    in1, in2;
-    int            i, j, maxener, *ind1, *ind2, *have;
-    gmx_enxnm_t   *enm1 = NULL, *enm2 = NULL;
-    t_enxframe    *fr1, *fr2;
-    gmx_bool       b1, b2;
-
-    fprintf(stdout, "comparing energy file %s and %s\n\n", fn1, fn2);
-
-    in1 = open_enx(fn1, "r");
-    in2 = open_enx(fn2, "r");
-    do_enxnms(in1, &nre1, &enm1);
-    do_enxnms(in2, &nre2, &enm2);
-    if (nre1 != nre2)
-    {
-        fprintf(stdout, "There are %d and %d terms in the energy files\n\n",
-                nre1, nre2);
-    }
-    else
-    {
-        fprintf(stdout, "There are %d terms in the energy files\n\n", nre1);
-    }
-
-    snew(ind1, nre1);
-    snew(ind2, nre2);
-    snew(have, nre2);
-    nre = 0;
-    for (i = 0; i < nre1; i++)
-    {
-        for (j = 0; j < nre2; j++)
-        {
-            if (enernm_equal(enm1[i].name, enm2[j].name))
-            {
-                ind1[nre] = i;
-                ind2[nre] = j;
-                have[j]   = 1;
-                nre++;
-                break;
-            }
-        }
-        if (nre == 0 || ind1[nre-1] != i)
-        {
-            cmp_str(stdout, "enm", i, enm1[i].name, "-");
-        }
-    }
-    for (i = 0; i < nre2; i++)
-    {
-        if (have[i] == 0)
-        {
-            cmp_str(stdout, "enm", i, "-", enm2[i].name);
-        }
-    }
-
-    maxener = nre;
-    for (i = 0; i < nre; i++)
-    {
-        if ((lastener != NULL) && (std::strstr(enm1[i].name, lastener) != NULL))
-        {
-            maxener = i+1;
-            break;
-        }
-    }
-
-    fprintf(stdout, "There are %d terms to compare in the energy files\n\n",
-            maxener);
-
-    for (i = 0; i < maxener; i++)
-    {
-        cmp_str(stdout, "unit", i, enm1[ind1[i]].unit, enm2[ind2[i]].unit);
-    }
-
-    snew(fr1, 1);
-    snew(fr2, 1);
-    do
-    {
-        b1 = do_enx(in1, fr1);
-        b2 = do_enx(in2, fr2);
-        if (b1 && !b2)
-        {
-            fprintf(stdout, "\nEnd of file on %s but not on %s\n", fn2, fn1);
-        }
-        else if (!b1 && b2)
-        {
-            fprintf(stdout, "\nEnd of file on %s but not on %s\n", fn1, fn2);
-        }
-        else if (!b1 && !b2)
-        {
-            fprintf(stdout, "\nFiles read successfully\n");
-        }
-        else
-        {
-            cmp_real(stdout, "t", -1, fr1->t, fr2->t, ftol, abstol);
-            cmp_int(stdout, "step", -1, fr1->step, fr2->step);
-            /* We don't want to print the nre mismatch for every frame */
-            /* cmp_int(stdout,"nre",-1,fr1->nre,fr2->nre); */
-            if ((fr1->nre >= nre) && (fr2->nre >= nre))
-            {
-                cmp_energies(stdout, fr1->step, fr1->step, fr1->ener, fr2->ener,
-                             enm1, ftol, abstol, nre, ind1, ind2, maxener);
-            }
-            /*cmp_disres(fr1,fr2,ftol,abstol);*/
-            cmp_eblocks(fr1, fr2, ftol, abstol);
-        }
-    }
-    while (b1 && b2);
-
-    close_enx(in1);
-    close_enx(in2);
-
-    free_enxframe(fr2);
-    sfree(fr2);
-    free_enxframe(fr1);
-    sfree(fr1);
-}
index 5234d5d1d9262f88ba5cff7cfb147980691d700a..21303d4339e861d03d90f75924cf42b02dcfefdd 100644 (file)
@@ -45,6 +45,7 @@
 #include "gromacs/fileio/trrio.h"
 #include "gromacs/gmxpreprocess/readir.h"
 #include "gromacs/math/vec.h"
+#include "gromacs/mdrunutility/mdmodules.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/mdtypes/state.h"
@@ -266,7 +267,7 @@ static void reduce_topology_x(int gnx, int index[],
     int         *invindex;
     int          i;
 
-    top      = gmx_mtop_t_to_t_topology(mtop);
+    top      = gmx_mtop_t_to_t_topology(mtop, false);
     bKeep    = bKeepIt(gnx, top.atoms.nr, index);
     invindex = invind(gnx, top.atoms.nr, index);
 
@@ -327,57 +328,38 @@ static void zeroq(int index[], gmx_mtop_t *mtop)
 int gmx_convert_tpr(int argc, char *argv[])
 {
     const char       *desc[] = {
-        "[THISMODULE] can edit run input files in four ways.[PAR]",
+        "[THISMODULE] can edit run input files in three ways.[PAR]",
         "[BB]1.[bb] by modifying the number of steps in a run input file",
         "with options [TT]-extend[tt], [TT]-until[tt] or [TT]-nsteps[tt]",
         "(nsteps=-1 means unlimited number of steps)[PAR]",
-        "[BB]2.[bb] (OBSOLETE) by creating a run input file",
-        "for a continuation run when your simulation has crashed due to e.g.",
-        "a full disk, or by making a continuation run input file.",
-        "This option is obsolete, since mdrun now writes and reads",
-        "checkpoint files.",
-        "[BB]Note[bb] that a frame with coordinates and velocities is needed.",
-        "When pressure and/or Nose-Hoover temperature coupling is used",
-        "an energy file can be supplied to get an exact continuation",
-        "of the original run.[PAR]",
-        "[BB]3.[bb] by creating a [REF].tpx[ref] file for a subset of your original",
+        "[BB]2.[bb] by creating a [REF].tpx[ref] file for a subset of your original",
         "tpx file, which is useful when you want to remove the solvent from",
         "your [REF].tpx[ref] file, or when you want to make e.g. a pure C[GRK]alpha[grk] [REF].tpx[ref] file.",
         "Note that you may need to use [TT]-nsteps -1[tt] (or similar) to get",
         "this to work.",
         "[BB]WARNING: this [REF].tpx[ref] file is not fully functional[bb].[PAR]",
-        "[BB]4.[bb] by setting the charges of a specified group",
+        "[BB]3.[bb] by setting the charges of a specified group",
         "to zero. This is useful when doing free energy estimates",
         "using the LIE (Linear Interaction Energy) method."
     };
 
-    const char       *top_fn, *frame_fn;
-    struct t_fileio  *fp;
-    ener_file_t       fp_ener = NULL;
-    gmx_trr_header_t  head;
+    const char       *top_fn;
     int               i;
-    gmx_int64_t       nsteps_req, run_step, frame;
+    gmx_int64_t       nsteps_req, run_step;
     double            run_t, state_t;
-    gmx_bool          bOK, bNsteps, bExtend, bUntil, bTime, bTraj;
-    gmx_bool          bFrame, bUse, bSel, bNeedEner, bReadEner, bScanEner, bFepState;
+    gmx_bool          bSel;
+    gmx_bool          bNsteps, bExtend, bUntil;
     gmx_mtop_t        mtop;
     t_atoms           atoms;
     t_inputrec       *ir;
     t_state           state;
-    rvec             *newx = NULL, *newv = NULL, *tmpx, *tmpv;
-    matrix            newbox;
     int               gnx;
     char             *grpname;
     int              *index = NULL;
-    int               nre;
-    gmx_enxnm_t      *enm     = NULL;
-    t_enxframe       *fr_ener = NULL;
     char              buf[200], buf2[200];
     gmx_output_env_t *oenv;
     t_filenm          fnm[] = {
         { efTPR, NULL,  NULL,    ffREAD  },
-        { efTRN, "-f",  NULL,    ffOPTRD },
-        { efEDR, "-e",  NULL,    ffOPTRD },
         { efNDX, NULL,  NULL,    ffOPTRD },
         { efTPR, "-o",  "tprout", ffWRITE }
     };
@@ -385,9 +367,8 @@ int gmx_convert_tpr(int argc, char *argv[])
 
     /* Command line options */
     static int      nsteps_req_int = 0;
-    static real     start_t        = -1.0, extend_t = 0.0, until_t = 0.0;
-    static int      init_fep_state = 0;
-    static gmx_bool bContinuation  = TRUE, bZeroQ = FALSE, bVel = TRUE;
+    static real     extend_t       = 0.0, until_t = 0.0;
+    static gmx_bool bZeroQ         = FALSE;
     static t_pargs  pa[]           = {
         { "-extend",        FALSE, etREAL, {&extend_t},
           "Extend runtime by this amount (ps)" },
@@ -395,16 +376,8 @@ int gmx_convert_tpr(int argc, char *argv[])
           "Extend runtime until this ending time (ps)" },
         { "-nsteps",        FALSE, etINT,  {&nsteps_req_int},
           "Change the number of steps" },
-        { "-time",          FALSE, etREAL, {&start_t},
-          "Continue from frame at this time (ps) instead of the last frame" },
         { "-zeroq",         FALSE, etBOOL, {&bZeroQ},
-          "Set the charges of a group (from the index) to zero" },
-        { "-vel",           FALSE, etBOOL, {&bVel},
-          "Require velocities from trajectory" },
-        { "-cont",          FALSE, etBOOL, {&bContinuation},
-          "For exact continuation, the constraints should not be applied before the first step" },
-        { "-init_fep_state", FALSE, etINT, {&init_fep_state},
-          "fep state to initialize from" },
+          "Set the charges of a group (from the index) to zero" }
     };
 
     /* Parse the command line */
@@ -419,195 +392,16 @@ int gmx_convert_tpr(int argc, char *argv[])
     bNsteps    = opt2parg_bSet("-nsteps", asize(pa), pa);
     bExtend    = opt2parg_bSet("-extend", asize(pa), pa);
     bUntil     = opt2parg_bSet("-until", asize(pa), pa);
-    bFepState  = opt2parg_bSet("-init_fep_state", asize(pa), pa);
-    bTime      = opt2parg_bSet("-time", asize(pa), pa);
-    bTraj      = (opt2bSet("-f", NFILE, fnm) || bTime);
 
     top_fn = ftp2fn(efTPR, NFILE, fnm);
     fprintf(stderr, "Reading toplogy and stuff from %s\n", top_fn);
 
-    snew(ir, 1);
+    gmx::MDModules mdModules;
+    ir = mdModules.inputrec();
     read_tpx_state(top_fn, ir, &state, &mtop);
     run_step = ir->init_step;
     run_t    = ir->init_step*ir->delta_t + ir->init_t;
 
-    if (!EI_STATE_VELOCITY(ir->eI))
-    {
-        bVel = FALSE;
-    }
-
-    if (bTraj)
-    {
-        fprintf(stderr, "\n"
-                "NOTE: Reading the state from trajectory is an obsolete feature of gmx convert-tpr.\n"
-                "      Continuation should be done by loading a checkpoint file with mdrun -cpi\n"
-                "      This guarantees that all state variables are transferred.\n"
-                "      gmx convert-tpr is now only useful for increasing nsteps,\n"
-                "      but even that can often be avoided by using mdrun -maxh\n"
-                "\n");
-
-        if (ir->bContinuation != bContinuation)
-        {
-            fprintf(stderr, "Modifying ir->bContinuation to %s\n",
-                    gmx::boolToString(bContinuation));
-        }
-        ir->bContinuation = bContinuation;
-
-
-        bNeedEner = (ir->epc == epcPARRINELLORAHMAN || ir->etc == etcNOSEHOOVER);
-        bReadEner = (bNeedEner && ftp2bSet(efEDR, NFILE, fnm));
-        bScanEner = (bReadEner && !bTime);
-
-        if (ir->epc != epcNO || EI_SD(ir->eI) || ir->eI == eiBD)
-        {
-            fprintf(stderr, "NOTE: The simulation uses pressure coupling and/or stochastic dynamics.\n"
-                    "gmx convert-tpr can not provide binary identical continuation.\n"
-                    "If you want that, supply a checkpoint file to mdrun\n\n");
-        }
-
-        if (EI_SD(ir->eI) || ir->eI == eiBD)
-        {
-            fprintf(stderr, "\nChanging ld-seed from %" GMX_PRId64 " ", ir->ld_seed);
-            ir->ld_seed = static_cast<int>(gmx::makeRandomSeed());
-            fprintf(stderr, "to %" GMX_PRId64 "\n\n", ir->ld_seed);
-        }
-
-        frame_fn = ftp2fn(efTRN, NFILE, fnm);
-
-        if (fn2ftp(frame_fn) == efCPT)
-        {
-            int sim_part;
-
-            fprintf(stderr,
-                    "\nREADING STATE FROM CHECKPOINT %s...\n\n",
-                    frame_fn);
-
-            read_checkpoint_state(frame_fn, &sim_part,
-                                  &run_step, &run_t, &state);
-        }
-        else
-        {
-            fprintf(stderr,
-                    "\nREADING COORDS, VELS AND BOX FROM TRAJECTORY %s...\n\n",
-                    frame_fn);
-
-            fp = gmx_trr_open(frame_fn, "r");
-            if (bScanEner)
-            {
-                fp_ener = open_enx(ftp2fn(efEDR, NFILE, fnm), "r");
-                do_enxnms(fp_ener, &nre, &enm);
-                snew(fr_ener, 1);
-                fr_ener->t = -1e-12;
-            }
-
-            /* Now scan until the last set of x and v (step == 0)
-             * or the ones at step step.
-             */
-            bFrame = TRUE;
-            frame  = 0;
-            while (bFrame)
-            {
-                bFrame = gmx_trr_read_frame_header(fp, &head, &bOK);
-                if (bOK && frame == 0)
-                {
-                    if (mtop.natoms != head.natoms)
-                    {
-                        gmx_fatal(FARGS, "Number of atoms in Topology (%d) "
-                                  "is not the same as in Trajectory (%d)\n",
-                                  mtop.natoms, head.natoms);
-                    }
-                    snew(newx, head.natoms);
-                    snew(newv, head.natoms);
-                }
-                bFrame = bFrame && bOK;
-                if (bFrame)
-                {
-                    bOK = gmx_trr_read_frame_data(fp, &head, newbox, newx, newv, NULL);
-                }
-                bFrame = bFrame && bOK;
-                bUse   = FALSE;
-                if (bFrame &&
-                    (head.x_size) && (head.v_size || !bVel))
-                {
-                    bUse = TRUE;
-                    if (bScanEner)
-                    {
-                        /* Read until the energy time is >= the trajectory time */
-                        while (fr_ener->t < head.t && do_enx(fp_ener, fr_ener))
-                        {
-                            ;
-                        }
-                        bUse = (fr_ener->t == head.t);
-                    }
-                    if (bUse)
-                    {
-                        tmpx                  = newx;
-                        newx                  = state.x;
-                        state.x               = tmpx;
-                        tmpv                  = newv;
-                        newv                  = state.v;
-                        state.v               = tmpv;
-                        run_t                 = head.t;
-                        run_step              = head.step;
-                        state.fep_state       = head.fep_state;
-                        state.lambda[efptFEP] = head.lambda;
-                        copy_mat(newbox, state.box);
-                    }
-                }
-                if (bFrame || !bOK)
-                {
-                    sprintf(buf, "\r%s %s frame %s%s: step %s%s time %s",
-                            "%s", "%s", "%6", GMX_PRId64, "%6", GMX_PRId64, " %8.3f");
-                    fprintf(stderr, buf,
-                            bUse ? "Read   " : "Skipped", ftp2ext(fn2ftp(frame_fn)),
-                            frame, head.step, head.t);
-                    fflush(stderr);
-                    frame++;
-                    if (bTime && (head.t >= start_t))
-                    {
-                        bFrame = FALSE;
-                    }
-                }
-            }
-            if (bScanEner)
-            {
-                close_enx(fp_ener);
-                free_enxframe(fr_ener);
-                free_enxnms(nre, enm);
-            }
-            gmx_trr_close(fp);
-            fprintf(stderr, "\n");
-
-            if (!bOK)
-            {
-                fprintf(stderr, "%s frame %s (step %s, time %g) is incomplete\n",
-                        ftp2ext(fn2ftp(frame_fn)), gmx_step_str(frame-1, buf2),
-                        gmx_step_str(head.step, buf), head.t);
-            }
-            fprintf(stderr, "\nUsing frame of step %s time %g\n",
-                    gmx_step_str(run_step, buf), run_t);
-
-            if (bNeedEner)
-            {
-                if (bReadEner)
-                {
-                    get_enx_state(ftp2fn(efEDR, NFILE, fnm), run_t, &mtop.groups, ir, &state);
-                }
-                else
-                {
-                    fprintf(stderr, "\nWARNING: The simulation uses %s temperature and/or %s pressure coupling,\n"
-                            "         the continuation will only be exact when an energy file is supplied\n\n",
-                            ETCOUPLTYPE(etcNOSEHOOVER),
-                            EPCOUPLTYPE(epcPARRINELLORAHMAN));
-                }
-            }
-            if (bFepState)
-            {
-                ir->fepvals->init_fep_state = init_fep_state;
-            }
-        }
-    }
-
     if (bNsteps)
     {
         fprintf(stderr, "Setting nsteps to %s\n", gmx_step_str(nsteps_req, buf));
@@ -646,7 +440,7 @@ int gmx_convert_tpr(int argc, char *argv[])
         ir->init_step = run_step;
 
         if (ftp2bSet(efNDX, NFILE, fnm) ||
-            !(bNsteps || bExtend || bUntil || bTraj))
+            !(bNsteps || bExtend || bUntil))
         {
             atoms = gmx_mtop_global_atoms(&mtop);
             get_index(&atoms, ftp2fn_null(efNDX, NFILE, fnm), 1,
@@ -667,7 +461,7 @@ int gmx_convert_tpr(int argc, char *argv[])
             {
                 fprintf(stderr, "Will write subset %s of original tpx containing %d "
                         "atoms\n", grpname, gnx);
-                reduce_topology_x(gnx, index, &mtop, state.x, state.v);
+                reduce_topology_x(gnx, index, &mtop, as_rvec_array(state.x.data()), as_rvec_array(state.v.data()));
                 state.natoms = gnx;
             }
             else if (bZeroQ)
index 9ddd8ec035d0cbc1151c6b14d1337caba69eecac..0c421ffd83c54e8b9b06d743c96c7c0b6ab633cc 100644 (file)
 #include "gromacs/fileio/gmxfio.h"
 #include "gromacs/fileio/mtxio.h"
 #include "gromacs/fileio/tngio.h"
-#include "gromacs/fileio/tngio_for_tools.h"
 #include "gromacs/fileio/tpxio.h"
 #include "gromacs/fileio/trrio.h"
 #include "gromacs/fileio/xtcio.h"
 #include "gromacs/gmxpreprocess/gmxcpp.h"
 #include "gromacs/linearalgebra/sparsematrix.h"
 #include "gromacs/math/vecdump.h"
+#include "gromacs/mdrunutility/mdmodules.h"
 #include "gromacs/mdtypes/forcerec.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/txtdump.h"
 
-static void list_tpx(const char *fn, gmx_bool bShowNumbers, const char *mdpfn,
-                     gmx_bool bSysTop)
+static void list_tpx(const char *fn,
+                     gmx_bool    bShowNumbers,
+                     gmx_bool    bShowParameters,
+                     const char *mdpfn,
+                     gmx_bool    bSysTop)
 {
     FILE         *gp;
     int           indent, i, j, **gcount, atot;
-    t_state       state;
-    t_inputrec    ir;
+    t_state       state {};
+    t_inputrec   *ir = nullptr;
     t_tpxheader   tpx;
     gmx_mtop_t    mtop;
     gmx_groups_t *groups;
     t_topology    top;
 
     read_tpxheader(fn, &tpx, TRUE);
-
+    gmx::MDModules mdModules;
+    if (tpx.bIr)
+    {
+        ir = mdModules.inputrec();
+    }
     read_tpx_state(fn,
-                   tpx.bIr  ? &ir : NULL,
+                   ir,
                    &state,
                    tpx.bTop ? &mtop : NULL);
 
     if (mdpfn && tpx.bIr)
     {
         gp = gmx_fio_fopen(mdpfn, "w");
-        pr_inputrec(gp, 0, NULL, &(ir), TRUE);
+        pr_inputrec(gp, 0, NULL, ir, TRUE);
         gmx_fio_fclose(gp);
     }
 
@@ -100,24 +107,24 @@ static void list_tpx(const char *fn, gmx_bool bShowNumbers, const char *mdpfn,
     {
         if (bSysTop)
         {
-            top = gmx_mtop_t_to_t_topology(&mtop);
+            top = gmx_mtop_t_to_t_topology(&mtop, false);
         }
 
         if (available(stdout, &tpx, 0, fn))
         {
             indent = 0;
             pr_title(stdout, indent, fn);
-            pr_inputrec(stdout, 0, "inputrec", tpx.bIr ? &(ir) : NULL, FALSE);
+            pr_inputrec(stdout, 0, "inputrec", ir, FALSE);
 
             pr_tpxheader(stdout, indent, "header", &(tpx));
 
             if (!bSysTop)
             {
-                pr_mtop(stdout, indent, "topology", &(mtop), bShowNumbers);
+                pr_mtop(stdout, indent, "topology", &(mtop), bShowNumbers, bShowParameters);
             }
             else
             {
-                pr_top(stdout, indent, "topology", &(top), bShowNumbers);
+                pr_top(stdout, indent, "topology", &(top), bShowNumbers, bShowParameters);
             }
 
             pr_rvecs(stdout, indent, "box", tpx.bBox ? state.box : NULL, DIM);
@@ -127,11 +134,11 @@ static void list_tpx(const char *fn, gmx_bool bShowNumbers, const char *mdpfn,
             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_xi", state.nosehoover_xi.data(), 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);
+            pr_rvecs(stdout, indent, "x", tpx.bX ? as_rvec_array(state.x.data()) : NULL, state.natoms);
+            pr_rvecs(stdout, indent, "v", tpx.bV ? as_rvec_array(state.v.data()) : NULL, state.natoms);
         }
 
         groups = &mtop.groups;
@@ -164,7 +171,6 @@ static void list_tpx(const char *fn, gmx_bool bShowNumbers, const char *mdpfn,
         }
         sfree(gcount);
     }
-    done_state(&state);
 }
 
 static void list_top(const char *fn)
@@ -620,9 +626,11 @@ int gmx_dump(int argc, char *argv[])
     gmx_output_env_t *oenv;
     /* Command line options */
     static gmx_bool   bShowNumbers = TRUE;
+    static gmx_bool   bShowParams  = FALSE;
     static gmx_bool   bSysTop      = FALSE;
     t_pargs           pa[]         = {
         { "-nr", FALSE, etBOOL, {&bShowNumbers}, "Show index numbers in output (leaving them out makes comparison easier, but creates a useless topology)" },
+        { "-param", FALSE, etBOOL, {&bShowParams}, "Show parameters for each bonded interaction (for comparing dumps, it is useful to combine this with -nonr)" },
         { "-sys", FALSE, etBOOL, {&bSysTop}, "List the atoms and bonded interactions for the whole system instead of for each molecule type" }
     };
 
@@ -635,7 +643,7 @@ int gmx_dump(int argc, char *argv[])
 
     if (ftp2bSet(efTPR, NFILE, fnm))
     {
-        list_tpx(ftp2fn(efTPR, NFILE, fnm), bShowNumbers,
+        list_tpx(ftp2fn(efTPR, NFILE, fnm), bShowNumbers, bShowParams,
                  ftp2fn_null(efMDP, NFILE, fnm), bSysTop);
     }
     else if (ftp2bSet(efTRX, NFILE, fnm))
index cc04615c90aa68ed1d6a7207be706889c496aaba..c23339aed64440fb43537cae01254b2aa5664c5e 100644 (file)
 
 #include <algorithm>
 
+#include "gromacs/topology/atomprop.h"
 #include "gromacs/topology/symtab.h"
+#include "gromacs/utility/compare.h"
+#include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/txtdump.h"
 
@@ -53,14 +56,19 @@ const char *ptype_str[eptNR+1] = {
 
 void init_atom(t_atoms *at)
 {
-    at->nr        = 0;
-    at->nres      = 0;
-    at->atom      = NULL;
-    at->resinfo   = NULL;
-    at->atomname  = NULL;
-    at->atomtype  = NULL;
-    at->atomtypeB = NULL;
-    at->pdbinfo   = NULL;
+    at->nr          = 0;
+    at->nres        = 0;
+    at->atom        = NULL;
+    at->resinfo     = NULL;
+    at->atomname    = NULL;
+    at->atomtype    = NULL;
+    at->atomtypeB   = NULL;
+    at->pdbinfo     = NULL;
+    at->haveMass    = FALSE;
+    at->haveCharge  = FALSE;
+    at->haveType    = FALSE;
+    at->haveBState  = FALSE;
+    at->havePdbInfo = FALSE;
 }
 
 void init_atomtypes(t_atomtypes *at)
@@ -154,7 +162,12 @@ void init_t_atoms(t_atoms *atoms, int natoms, gmx_bool bPdbinfo)
     atoms->atomtypeB = NULL;
     snew(atoms->resinfo, natoms);
     snew(atoms->atom, natoms);
-    if (bPdbinfo)
+    atoms->haveMass    = FALSE;
+    atoms->haveCharge  = FALSE;
+    atoms->haveType    = FALSE;
+    atoms->haveBState  = FALSE;
+    atoms->havePdbInfo = bPdbinfo;
+    if (atoms->havePdbInfo)
     {
         snew(atoms->pdbinfo, natoms);
     }
@@ -326,3 +339,92 @@ void pr_atomtypes(FILE *fp, int indent, const char *title, const t_atomtypes *at
         }
     }
 }
+
+static void cmp_atom(FILE *fp, int index, const t_atom *a1, const t_atom *a2, real ftol, real abstol)
+{
+    if (a2)
+    {
+        cmp_us(fp, "atom.type", index, a1->type, a2->type);
+        cmp_us(fp, "atom.ptype", index, a1->ptype, a2->ptype);
+        cmp_int(fp, "atom.resind", index, a1->resind, a2->resind);
+        cmp_int(fp, "atom.atomnumber", index, a1->atomnumber, a2->atomnumber);
+        cmp_real(fp, "atom.m", index, a1->m, a2->m, ftol, abstol);
+        cmp_real(fp, "atom.q", index, a1->q, a2->q, ftol, abstol);
+        cmp_us(fp, "atom.typeB", index, a1->typeB, a2->typeB);
+        cmp_real(fp, "atom.mB", index, a1->mB, a2->mB, ftol, abstol);
+        cmp_real(fp, "atom.qB", index, a1->qB, a2->qB, ftol, abstol);
+    }
+    else
+    {
+        cmp_us(fp, "atom.type", index, a1->type, a1->typeB);
+        cmp_real(fp, "atom.m", index, a1->m, a1->mB, ftol, abstol);
+        cmp_real(fp, "atom.q", index, a1->q, a1->qB, ftol, abstol);
+    }
+}
+
+void cmp_atoms(FILE *fp, const t_atoms *a1, const t_atoms *a2, real ftol, real abstol)
+{
+    int i;
+
+    fprintf(fp, "comparing atoms\n");
+
+    if (a2)
+    {
+        cmp_int(fp, "atoms->nr", -1, a1->nr, a2->nr);
+        for (i = 0; (i < a1->nr); i++)
+        {
+            cmp_atom(fp, i, &(a1->atom[i]), &(a2->atom[i]), ftol, abstol);
+        }
+    }
+    else
+    {
+        for (i = 0; (i < a1->nr); i++)
+        {
+            cmp_atom(fp, i, &(a1->atom[i]), NULL, ftol, abstol);
+        }
+    }
+}
+
+void atomsSetMassesBasedOnNames(t_atoms *atoms, gmx_bool printMissingMasses)
+{
+    if (atoms->haveMass)
+    {
+        /* We could decide to anyhow assign then or generate a fatal error,
+         * but it's probably most useful to keep the masses we have.
+         */
+        return;
+    }
+
+    int            maxWarn  = (printMissingMasses ? 10 : 0);
+    int            numWarn  = 0;
+
+    gmx_atomprop_t aps      = gmx_atomprop_init();
+
+    gmx_bool       haveMass = TRUE;
+    for (int i = 0; i < atoms->nr; i++)
+    {
+        if (!gmx_atomprop_query(aps, epropMass,
+                                *atoms->resinfo[atoms->atom[i].resind].name,
+                                *atoms->atomname[i],
+                                &atoms->atom[i].m))
+        {
+            haveMass = FALSE;
+
+            if (numWarn < maxWarn)
+            {
+                fprintf(stderr, "Can not find mass in database for atom %s in residue %d %s\n",
+                        *atoms->atomname[i],
+                        atoms->resinfo[atoms->atom[i].resind].nr,
+                        *atoms->resinfo[atoms->atom[i].resind].name);
+                numWarn++;
+            }
+            else
+            {
+                break;
+            }
+        }
+    }
+    atoms->haveMass = haveMass;
+
+    gmx_atomprop_destroy(aps);
+}
index faadaa98a3caba907454d3f66239ef0d91584d3f..8bb674b67d1845e908e55de6f449a8e628d44160 100644 (file)
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 struct t_symtab;
 
 /* The particle type */
@@ -107,19 +103,29 @@ typedef struct t_grps
 
 typedef struct t_atoms
 {
-    int            nr;          /* Nr of atoms                          */
-    t_atom        *atom;        /* Array of atoms (dim: nr)             */
+    int          nr;            /* Nr of atoms                          */
+    t_atom      *atom;          /* Array of atoms (dim: nr)             */
                                 /* The following entries will not       */
                                 /* always be used (nres==0)             */
-    char          ***atomname;  /* Array of pointers to atom name       */
+    char      ***atomname;      /* Array of pointers to atom name       */
                                 /* use: (*(atomname[i]))                */
-    char          ***atomtype;  /* Array of pointers to atom types      */
+    char      ***atomtype;      /* Array of pointers to atom types      */
                                 /* use: (*(atomtype[i]))                */
-    char          ***atomtypeB; /* Array of pointers to B atom types    */
+    char      ***atomtypeB;     /* Array of pointers to B atom types    */
                                 /* use: (*(atomtypeB[i]))               */
-    int              nres;      /* The number of resinfo entries        */
-    t_resinfo       *resinfo;   /* Array of residue names and numbers   */
-    t_pdbinfo       *pdbinfo;   /* PDB Information, such as aniso. Bfac */
+    int          nres;          /* The number of resinfo entries        */
+    t_resinfo   *resinfo;       /* Array of residue names and numbers   */
+    t_pdbinfo   *pdbinfo;       /* PDB Information, such as aniso. Bfac */
+
+    /* Flags that tell if properties are set for all nr atoms.
+     * For B-state parameters, both haveBState and the mass/charge/type
+     * flag should be TRUE.
+     */
+    gmx_bool     haveMass;      /* Mass available                       */
+    gmx_bool     haveCharge;    /* Charge available                     */
+    gmx_bool     haveType;      /* Atom type available                  */
+    gmx_bool     haveBState;    /* B-state parameters available         */
+    gmx_bool     havePdbInfo;   /* pdbinfo available                    */
 } t_atoms;
 
 typedef struct t_atomtypes
@@ -164,8 +170,14 @@ void pr_atoms(FILE *fp, int indent, const char *title, const t_atoms *atoms,
 void pr_atomtypes(FILE *fp, int indent, const char *title,
                   const t_atomtypes *atomtypes, gmx_bool bShowNumbers);
 
-#ifdef __cplusplus
-}
-#endif
+void cmp_atoms(FILE *fp, const t_atoms *a1, const t_atoms *a2, real ftol, real abstol);
+
+/*! \brief Set mass for each atom using the atom and residue names using a database
+ *
+ * If atoms->haveMass = TRUE does nothing.
+ * If printMissingMasss = TRUE, prints details for first 10 missing masses
+ * to stderr.
+ */
+void atomsSetMassesBasedOnNames(t_atoms *atoms, gmx_bool printMissingMasses);
 
 #endif
index 0ad6cbba67d47f31e0997c5fef4da5a079bf6dfb..4806c2a9ba889416ba5dba0afecc4fbac3f85ecc 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -303,7 +303,9 @@ void pr_iparams(FILE *fp, t_functype ftype, const t_iparams *iparams)
 }
 
 void pr_ilist(FILE *fp, int indent, const char *title,
-              const t_functype *functype, const t_ilist *ilist, gmx_bool bShowNumbers)
+              const t_functype *functype, const t_ilist *ilist,
+              gmx_bool bShowNumbers,
+              gmx_bool bShowParameters, const t_iparams *iparams)
 {
     int      i, j, k, type, ftype;
     t_iatom *iatoms;
@@ -320,24 +322,26 @@ void pr_ilist(FILE *fp, int indent, const char *title,
             iatoms = ilist->iatoms;
             for (i = j = 0; i < ilist->nr; )
             {
-#ifndef DEBUG
                 pr_indent(fp, indent+INDENT);
                 type  = *(iatoms++);
                 ftype = functype[type];
-                fprintf(fp, "%d type=%d (%s)",
-                        bShowNumbers ? j : -1, bShowNumbers ? type : -1,
-                        interaction_function[ftype].name);
+                if (bShowNumbers)
+                {
+                    fprintf(fp, "%d type=%d ", j, type);
+                }
                 j++;
+                printf("(%s)", interaction_function[ftype].name);
                 for (k = 0; k < interaction_function[ftype].nratoms; k++)
                 {
-                    fprintf(fp, " %d", *(iatoms++));
+                    fprintf(fp, " %3d", *(iatoms++));
+                }
+                if (bShowParameters)
+                {
+                    fprintf(fp, "  ");
+                    pr_iparams(fp, ftype,  &iparams[type]);
                 }
                 fprintf(fp, "\n");
                 i += 1+interaction_function[ftype].nratoms;
-#else
-                fprintf(fp, "%5d%5d\n", i, iatoms[i]);
-                i++;
-#endif
             }
         }
     }
@@ -406,7 +410,8 @@ void pr_ffparams(FILE *fp, int indent, const char *title,
     pr_cmap(fp, indent, "cmap", &ffparams->cmap_grid, bShowNumbers);
 }
 
-void pr_idef(FILE *fp, int indent, const char *title, const t_idef *idef, gmx_bool bShowNumbers)
+void pr_idef(FILE *fp, int indent, const char *title, const t_idef *idef,
+             gmx_bool bShowNumbers, gmx_bool bShowParameters)
 {
     int i, j;
 
@@ -430,7 +435,8 @@ void pr_idef(FILE *fp, int indent, const char *title, const t_idef *idef, gmx_bo
         for (j = 0; (j < F_NRE); j++)
         {
             pr_ilist(fp, indent, interaction_function[j].longname,
-                     idef->functype, &idef->il[j], bShowNumbers);
+                     idef->functype, &idef->il[j], bShowNumbers,
+                     bShowParameters, idef->iparams);
         }
     }
 }
index 4446a3f170b3dc82e71ae49dae99bd3d38de18c1..467d7d45f8ad189bf717a5661e1738314a6d836a 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -406,10 +406,13 @@ typedef struct t_idef
 
 void pr_iparams(FILE *fp, t_functype ftype, const t_iparams *iparams);
 void pr_ilist(FILE *fp, int indent, const char *title,
-              const t_functype *functype, const t_ilist *ilist, gmx_bool bShowNumbers);
+              const t_functype *functype, const t_ilist *ilist,
+              gmx_bool bShowNumbers,
+              gmx_bool bShowParameters, const t_iparams *iparams);
 void pr_ffparams(FILE *fp, int indent, const char *title,
                  const gmx_ffparams_t *ffparams, gmx_bool bShowNumbers);
-void pr_idef(FILE *fp, int indent, const char *title, const t_idef *idef, gmx_bool bShowNumbers);
+void pr_idef(FILE *fp, int indent, const char *title, const t_idef *idef,
+             gmx_bool bShowNumbers, gmx_bool bShowParameters);
 
 #ifdef __cplusplus
 }
index 0825ef1e667bf35cf21fe9c55fd67aec3784bc18..ace7395591bca39e5118ae29a4b5d8fc76f791ba 100644 (file)
@@ -85,14 +85,11 @@ void write_index(const char *outf, t_blocka *b, char **gnames, gmx_bool bDuplica
     /* fprintf(out,"%5d  %5d\n",b->nr,b->nra); */
     for (i = 0; (i < b->nr); i++)
     {
-        fprintf(out, "[ %s ]\n", gnames[i]);
+        fprintf(out, "[ %s ]", gnames[i]);
         for (k = 0, j = b->index[i]; j < b->index[i+1]; j++, k++)
         {
-            fprintf(out, "%4d ", b->a[j]+1);
-            if ((k % 15) == 14)
-            {
-                fprintf(out, "\n");
-            }
+            const char sep = (k % 15 == 0 ? '\n' : ' ');
+            fprintf(out, "%c%4d", sep, b->a[j]+1);
         }
         fprintf(out, "\n");
     }
@@ -103,14 +100,11 @@ void write_index(const char *outf, t_blocka *b, char **gnames, gmx_bool bDuplica
         fprintf(stderr, "Duplicating the whole system with an atom offset of %d atoms.\n", natoms);
         for (i = 0; (i < b->nr); i++)
         {
-            fprintf(out, "[ %s_copy ]\n", gnames[i]);
+            fprintf(out, "[ %s_copy ]", gnames[i]);
             for (k = 0, j = b->index[i]; j < b->index[i+1]; j++, k++)
             {
-                fprintf(out, "%4d ", b->a[j]+1 + natoms );
-                if ((k % 15) == 14)
-                {
-                    fprintf(out, "\n");
-                }
+                const char sep = (k % 15 == 0 ? '\n' : ' ');
+                fprintf(out, "%c%4d", sep, b->a[j]+1 + natoms);
             }
             fprintf(out, "\n");
         }
@@ -853,7 +847,6 @@ int find_group(const char *s, int ngrps, char **grpname)
     n         = strlen(s);
     aa        = -1;
     /* first look for whole name match */
-    if (aa == -1)
     {
         for (i = 0; i < ngrps; i++)
         {
diff --git a/src/gromacs/topology/mtop_lookup.h b/src/gromacs/topology/mtop_lookup.h
new file mode 100644 (file)
index 0000000..6a8b69f
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ *
+ * \brief This file contains inline functions to look up atom information
+ * using the global atom index.
+ *
+ * \author Berk Hess <hess@kth.se>
+ * \inlibraryapi
+ * \ingroup module_mtop
+ */
+
+#ifndef GMX_TOPOLOGY_MTOP_LOOKUP_H
+#define GMX_TOPOLOGY_MTOP_LOOKUP_H
+
+#include "gromacs/topology/topology.h"
+#include "gromacs/utility/basedefinitions.h"
+#include "gromacs/utility/gmxassert.h"
+
+struct t_atom;
+
+/*! \brief Look up the molecule block and other indices of a global atom index
+ *
+ * The atom index has to be in range: 0 <= \p globalAtomIndex < \p mtop->natoms.
+ * The input value of moleculeBlock should be in range. Use 0 as starting value.
+ * For subsequent calls to this function, e.g. in a loop, pass in the previously
+ * returned value for best performance. Atoms in a group tend to be in the same
+ * molecule(block), so this minimizes the search time.
+ *
+ * \param[in]     mtop                 The molecule topology
+ * \param[in]     globalAtomIndex      The global atom index to look up
+ * \param[in,out] moleculeBlock        The molecule block index in \p mtop
+ * \param[out]    moleculeIndex        The index of the molecule in the block, can be NULL
+ * \param[out]    atomIndexInMolecule  The atom index in the molecule, can be NULL
+ */
+static inline void
+mtopGetMolblockIndex(const gmx_mtop_t *mtop,
+                     int               globalAtomIndex,
+                     int              *moleculeBlock,
+                     int              *moleculeIndex,
+                     int              *atomIndexInMolecule)
+{
+    GMX_ASSERT(globalAtomIndex >= 0 && globalAtomIndex < mtop->natoms, "The atom index to look up should be within range");
+    GMX_ASSERT(moleculeBlock != nullptr, "molBlock can not be NULL");
+    GMX_ASSERT(*moleculeBlock >= 0 && *moleculeBlock < mtop->nmolblock, "The starting molecule block index for the search should be within range");
+
+    /* Search the molecue block index using bisection */
+    int molBlock0 = -1;
+    int molBlock1 = mtop->nmolblock;
+
+    int globalAtomStart;
+    while (TRUE)
+    {
+        globalAtomStart = mtop->molblock[*moleculeBlock].globalAtomStart;
+        if (globalAtomIndex < globalAtomStart)
+        {
+            molBlock1 = *moleculeBlock;
+        }
+        else if (globalAtomIndex >= mtop->molblock[*moleculeBlock].globalAtomEnd)
+        {
+            molBlock0 = *moleculeBlock;
+        }
+        else
+        {
+            break;
+        }
+        *moleculeBlock = ((molBlock0 + molBlock1 + 1) >> 1);
+    }
+
+    int molIndex = (globalAtomIndex - globalAtomStart) / mtop->molblock[*moleculeBlock].natoms_mol;
+    if (moleculeIndex != nullptr)
+    {
+        *moleculeIndex = molIndex;
+    }
+    if (atomIndexInMolecule != nullptr)
+    {
+        *atomIndexInMolecule = globalAtomIndex - globalAtomStart - molIndex*mtop->molblock[*moleculeBlock].natoms_mol;
+    }
+}
+
+/*! \brief Returns the atom data for an atom based on global atom index
+ *
+ * The atom index has to be in range: 0 <= \p globalAtomIndex < \p mtop->natoms.
+ * The input value of moleculeBlock should be in range. Use 0 as starting value.
+ * For subsequent calls to this function, e.g. in a loop, pass in the previously
+ * returned value for best performance. Atoms in a group tend to be in the same
+ * molecule(block), so this minimizes the search time.
+ *
+ * \param[in]     mtop                 The molecule topology
+ * \param[in]     globalAtomIndex      The global atom index to look up
+ * \param[in,out] moleculeBlock        The molecule block index in \p mtop
+ */
+static inline const t_atom &
+mtopGetAtomParameters(const gmx_mtop_t  *mtop,
+                      int                globalAtomIndex,
+                      int               *moleculeBlock)
+{
+    int atomIndexInMolecule;
+    mtopGetMolblockIndex(mtop, globalAtomIndex, moleculeBlock,
+                         NULL, &atomIndexInMolecule);
+    const gmx_moltype_t &moltype = mtop->moltype[mtop->molblock[*moleculeBlock].type];
+    return moltype.atoms.atom[atomIndexInMolecule];
+}
+
+/*! \brief Returns the mass of an atom based on global atom index
+ *
+ * Returns that A-state mass of the atom with global index \p globalAtomIndex.
+ * The atom index has to be in range: 0 <= \p globalAtomIndex < \p mtop->natoms.
+ * The input value of moleculeBlock should be in range. Use 0 as starting value.
+ * For subsequent calls to this function, e.g. in a loop, pass in the previously
+ * returned value for best performance. Atoms in a group tend to be in the same
+ * molecule(block), so this minimizes the search time.
+ *
+ * \param[in]     mtop                 The molecule topology
+ * \param[in]     globalAtomIndex      The global atom index to look up
+ * \param[in,out] moleculeBlock        The molecule block index in \p mtop
+ */
+static inline real
+mtopGetAtomMass(const gmx_mtop_t  *mtop,
+                int                globalAtomIndex,
+                int               *moleculeBlock)
+{
+    const t_atom &atom = mtopGetAtomParameters(mtop, globalAtomIndex, moleculeBlock);
+    return atom.m;
+}
+
+/*! \brief Look up the atom and residue name and residue number and index of a global atom index
+ *
+ * The atom index has to be in range: 0 <= \p globalAtomIndex < \p mtop->natoms.
+ * The input value of moleculeBlock should be in range. Use 0 as starting value.
+ * For subsequent calls to this function, e.g. in a loop, pass in the previously
+ * returned value for best performance. Atoms in a group tend to be in the same
+ * molecule(block), so this minimizes the search time.
+ * Note that this function does a (somewhat expensive) lookup. If you want
+ * to look up data sequentially for all atoms in a molecule or the system,
+ * use one of the mtop loop functionalities.
+ *
+ * \param[in]     mtop                The molecule topology
+ * \param[in]     globalAtomIndex     The global atom index to look up
+ * \param[in,out] moleculeBlock       The molecule block index in \p mtop
+ * \param[out]    atomName            The atom name, input can be NULL
+ * \param[out]    residueNumber       The residue number, input can be NULL
+ * \param[out]    residueName         The residue name, input can be NULL
+ * \param[out]    globalResidueIndex  The gobal residue index, input can be NULL
+ */
+static inline void
+mtopGetAtomAndResidueName(const gmx_mtop_t  *mtop,
+                          int                globalAtomIndex,
+                          int               *moleculeBlock,
+                          const char       **atomName,
+                          int               *residueNumber,
+                          const char       **residueName,
+                          int               *globalResidueIndex)
+{
+    int moleculeIndex;
+    int atomIndexInMolecule;
+    mtopGetMolblockIndex(mtop, globalAtomIndex, moleculeBlock,
+                         &moleculeIndex, &atomIndexInMolecule);
+
+    const gmx_molblock_t &molb  = mtop->molblock[*moleculeBlock];
+    const t_atoms        &atoms = mtop->moltype[molb.type].atoms;
+    if (atomName != nullptr)
+    {
+        *atomName = *(atoms.atomname[atomIndexInMolecule]);
+    }
+    if (residueNumber != nullptr)
+    {
+        if (atoms.nres > mtop->maxres_renum)
+        {
+            *residueNumber = atoms.resinfo[atoms.atom[atomIndexInMolecule].resind].nr;
+        }
+        else
+        {
+            /* Single residue molecule, keep counting */
+            *residueNumber = molb.residueNumberStart + moleculeIndex*atoms.nres + atoms.atom[atomIndexInMolecule].resind;
+        }
+    }
+    if (residueName != nullptr)
+    {
+        *residueName = *(atoms.resinfo[atoms.atom[atomIndexInMolecule].resind].name);
+    }
+    if (globalResidueIndex != nullptr)
+    {
+        *globalResidueIndex = molb.globalResidueStart + moleculeIndex*atoms.nres + atoms.atom[atomIndexInMolecule].resind;
+    }
+}
+
+/*! \brief Returns residue information for an atom based on global atom index
+ *
+ * The atom index has to be in range: 0 <= \p globalAtomIndex < \p mtop->natoms.
+ * The input value of moleculeBlock should be in range. Use 0 as starting value.
+ * For subsequent calls to this function, e.g. in a loop, pass in the previously
+ * returned value for best performance. Atoms in a group tend to be in the same
+ * molecule(block), so this minimizes the search time.
+ *
+ * \param[in]     mtop                 The molecule topology
+ * \param[in]     globalAtomIndex      The global atom index to look up
+ * \param[in,out] moleculeBlock        The molecule block index in \p mtop
+ */
+static inline const t_resinfo &
+mtopGetResidueInfo(const gmx_mtop_t  *mtop,
+                   int                globalAtomIndex,
+                   int               *moleculeBlock)
+{
+    int atomIndexInMolecule;
+    mtopGetMolblockIndex(mtop, globalAtomIndex, moleculeBlock,
+                         NULL, &atomIndexInMolecule);
+    const gmx_moltype_t &moltype = mtop->moltype[mtop->molblock[*moleculeBlock].type];
+    const int            resind  = moltype.atoms.atom[atomIndexInMolecule].resind;
+    return moltype.atoms.resinfo[resind];
+}
+
+/*! \brief Returns PDB information for an atom based on global atom index
+ *
+ * The atom index has to be in range: 0 <= \p globalAtomIndex < \p mtop->natoms.
+ * The input value of moleculeBlock should be in range. Use 0 as starting value.
+ * For subsequent calls to this function, e.g. in a loop, pass in the previously
+ * returned value for best performance. Atoms in a group tend to be in the same
+ * molecule(block), so this minimizes the search time.
+ *
+ * \param[in]     mtop                 The molecule topology
+ * \param[in]     globalAtomIndex      The global atom index to look up
+ * \param[in,out] moleculeBlock        The molecule block index in \p mtop
+ */
+static inline const t_pdbinfo &
+mtopGetAtomPdbInfo(const gmx_mtop_t  *mtop,
+                   int                globalAtomIndex,
+                   int               *moleculeBlock)
+{
+    int atomIndexInMolecule;
+    mtopGetMolblockIndex(mtop, globalAtomIndex, moleculeBlock,
+                         NULL, &atomIndexInMolecule);
+    const gmx_moltype_t &moltype = mtop->moltype[mtop->molblock[*moleculeBlock].type];
+    GMX_ASSERT(moltype.atoms.havePdbInfo, "PDB information not present when requested");
+    return moltype.atoms.pdbinfo[atomIndexInMolecule];
+}
+
+#endif
index 5ec58477747454534a9b2b2726ebf992dffaefb0..9df64226446f4badaefae13c6194e74177c3f06d 100644 (file)
@@ -78,11 +78,47 @@ static int gmx_mtop_maxresnr(const gmx_mtop_t *mtop, int maxres_renum)
     return maxresnr;
 }
 
+static void finalizeMolblocks(gmx_mtop_t *mtop)
+{
+    int atomIndex          = 0;
+    int residueIndex       = 0;
+    int residueNumberStart = mtop->maxresnr + 1;
+    for (int mb = 0; mb < mtop->nmolblock; mb++)
+    {
+        gmx_molblock_t *molb          = &mtop->molblock[mb];
+        int             numResPerMol  = mtop->moltype[molb->type].atoms.nres;
+        molb->globalAtomStart         = atomIndex;
+        molb->globalResidueStart      = residueIndex;
+        atomIndex                    += molb->nmol*molb->natoms_mol;
+        residueIndex                 += molb->nmol*numResPerMol;
+        molb->globalAtomEnd           = atomIndex;
+        molb->residueNumberStart      = residueNumberStart;
+        if (numResPerMol <= mtop->maxres_renum)
+        {
+            residueNumberStart       += molb->nmol*numResPerMol;
+        }
+    }
+}
+
 void gmx_mtop_finalize(gmx_mtop_t *mtop)
 {
     char *env;
 
-    mtop->maxres_renum = 1;
+    if (mtop->nmolblock == 1 && mtop->molblock[0].nmol == 1)
+    {
+        /* We have a single molecule only, no renumbering needed.
+         * This case also covers an mtop converted from pdb/gro/... input,
+         * so we retain the original residue numbering.
+         */
+        mtop->maxres_renum = 0;
+    }
+    else
+    {
+        /* We only renumber single residue molecules. Their intra-molecular
+         * residue numbering is anyhow irrelevant.
+         */
+        mtop->maxres_renum = 1;
+    }
 
     env = getenv("GMX_MAXRESRENUM");
     if (env != NULL)
@@ -96,6 +132,8 @@ void gmx_mtop_finalize(gmx_mtop_t *mtop)
     }
 
     mtop->maxresnr = gmx_mtop_maxresnr(mtop, mtop->maxres_renum);
+
+    finalizeMolblocks(mtop);
 }
 
 void gmx_mtop_count_atomtypes(const gmx_mtop_t *mtop, int state, int typecount[])
@@ -142,6 +180,18 @@ int ncg_mtop(const gmx_mtop_t *mtop)
     return ncg;
 }
 
+int gmx_mtop_nres(const gmx_mtop_t *mtop)
+{
+    int nres = 0;
+    for (int mb = 0; mb < mtop->nmolblock; ++mb)
+    {
+        nres +=
+            mtop->molblock[mb].nmol*
+            mtop->moltype[mtop->molblock[mb].type].atoms.nres;
+    }
+    return nres;
+}
+
 void gmx_mtop_remove_chargegroups(gmx_mtop_t *mtop)
 {
     int      mt;
@@ -163,279 +213,6 @@ void gmx_mtop_remove_chargegroups(gmx_mtop_t *mtop)
     }
 }
 
-
-typedef struct
-{
-    int a_start;
-    int a_end;
-    int na_mol;
-} mb_at_t;
-
-typedef struct gmx_mtop_atomlookup
-{
-    const gmx_mtop_t *mtop;
-    int               nmb;
-    int               mb_start;
-    mb_at_t          *mba;
-} t_gmx_mtop_atomlookup;
-
-
-gmx_mtop_atomlookup_t
-gmx_mtop_atomlookup_init(const gmx_mtop_t *mtop)
-{
-    t_gmx_mtop_atomlookup *alook;
-    int                    mb;
-    int                    a_start, a_end, na, na_start = -1;
-
-    snew(alook, 1);
-
-    alook->mtop     = mtop;
-    alook->nmb      = mtop->nmolblock;
-    alook->mb_start = 0;
-    snew(alook->mba, alook->nmb);
-
-    a_start = 0;
-    for (mb = 0; mb < mtop->nmolblock; mb++)
-    {
-        na    = mtop->molblock[mb].nmol*mtop->molblock[mb].natoms_mol;
-        a_end = a_start + na;
-
-        alook->mba[mb].a_start = a_start;
-        alook->mba[mb].a_end   = a_end;
-        alook->mba[mb].na_mol  = mtop->molblock[mb].natoms_mol;
-
-        /* We start the binary search with the largest block */
-        if (mb == 0 || na > na_start)
-        {
-            alook->mb_start = mb;
-            na_start        = na;
-        }
-
-        a_start = a_end;
-    }
-
-    return alook;
-}
-
-gmx_mtop_atomlookup_t
-gmx_mtop_atomlookup_settle_init(const gmx_mtop_t *mtop)
-{
-    t_gmx_mtop_atomlookup *alook;
-    int                    mb;
-    int                    na, na_start = -1;
-
-    alook = gmx_mtop_atomlookup_init(mtop);
-
-    /* Check if the starting molblock has settle */
-    if (mtop->moltype[mtop->molblock[alook->mb_start].type].ilist[F_SETTLE].nr  == 0)
-    {
-        /* Search the largest molblock with settle */
-        alook->mb_start = -1;
-        for (mb = 0; mb < mtop->nmolblock; mb++)
-        {
-            if (mtop->moltype[mtop->molblock[mb].type].ilist[F_SETTLE].nr > 0)
-            {
-                na = alook->mba[mb].a_end - alook->mba[mb].a_start;
-                if (alook->mb_start == -1 || na > na_start)
-                {
-                    alook->mb_start = mb;
-                    na_start        = na;
-                }
-            }
-        }
-
-        if (alook->mb_start == -1)
-        {
-            gmx_incons("gmx_mtop_atomlookup_settle_init called without settles");
-        }
-    }
-
-    return alook;
-}
-
-void
-gmx_mtop_atomlookup_destroy(gmx_mtop_atomlookup_t alook)
-{
-    sfree(alook->mba);
-    sfree(alook);
-}
-
-void gmx_mtop_atomnr_to_atom(const gmx_mtop_atomlookup_t alook,
-                             int                         atnr_global,
-                             t_atom                    **atom)
-{
-    int mb0, mb1, mb;
-    int a_start, atnr_mol;
-
-#ifdef DEBUG_MTOP
-    if (atnr_global < 0 || atnr_global >= mtop->natoms)
-    {
-        gmx_fatal(FARGS, "gmx_mtop_atomnr_to_moltype was called with atnr_global=%d which is not in the atom range of this system (%d-%d)",
-                  atnr_global, 0, mtop->natoms-1);
-    }
-#endif
-
-    mb0 = -1;
-    mb1 = alook->nmb;
-    mb  = alook->mb_start;
-
-    while (TRUE)
-    {
-        a_start = alook->mba[mb].a_start;
-        if (atnr_global < a_start)
-        {
-            mb1 = mb;
-        }
-        else if (atnr_global >= alook->mba[mb].a_end)
-        {
-            mb0 = mb;
-        }
-        else
-        {
-            break;
-        }
-        mb = ((mb0 + mb1 + 1)>>1);
-    }
-
-    atnr_mol = (atnr_global - a_start) % alook->mba[mb].na_mol;
-
-    *atom = &alook->mtop->moltype[alook->mtop->molblock[mb].type].atoms.atom[atnr_mol];
-}
-
-void gmx_mtop_atomnr_to_ilist(const gmx_mtop_atomlookup_t alook,
-                              int atnr_global,
-                              t_ilist **ilist_mol, int *atnr_offset)
-{
-    int mb0, mb1, mb;
-    int a_start, atnr_local;
-
-#ifdef DEBUG_MTOP
-    if (atnr_global < 0 || atnr_global >= mtop->natoms)
-    {
-        gmx_fatal(FARGS, "gmx_mtop_atomnr_to_moltype was called with atnr_global=%d which is not in the atom range of this system (%d-%d)",
-                  atnr_global, 0, mtop->natoms-1);
-    }
-#endif
-
-    mb0 = -1;
-    mb1 = alook->nmb;
-    mb  = alook->mb_start;
-
-    while (TRUE)
-    {
-        a_start = alook->mba[mb].a_start;
-        if (atnr_global < a_start)
-        {
-            mb1 = mb;
-        }
-        else if (atnr_global >= alook->mba[mb].a_end)
-        {
-            mb0 = mb;
-        }
-        else
-        {
-            break;
-        }
-        mb = ((mb0 + mb1 + 1)>>1);
-    }
-
-    *ilist_mol = alook->mtop->moltype[alook->mtop->molblock[mb].type].ilist;
-
-    atnr_local = (atnr_global - a_start) % alook->mba[mb].na_mol;
-
-    *atnr_offset = atnr_global - atnr_local;
-}
-
-void gmx_mtop_atomnr_to_molblock_ind(const gmx_mtop_atomlookup_t alook,
-                                     int atnr_global,
-                                     int *molb, int *molnr, int *atnr_mol)
-{
-    int mb0, mb1, mb;
-    int a_start;
-
-#ifdef DEBUG_MTOP
-    if (atnr_global < 0 || atnr_global >= mtop->natoms)
-    {
-        gmx_fatal(FARGS, "gmx_mtop_atomnr_to_moltype was called with atnr_global=%d which is not in the atom range of this system (%d-%d)",
-                  atnr_global, 0, mtop->natoms-1);
-    }
-#endif
-
-    mb0 = -1;
-    mb1 = alook->nmb;
-    mb  = alook->mb_start;
-
-    while (TRUE)
-    {
-        a_start = alook->mba[mb].a_start;
-        if (atnr_global < a_start)
-        {
-            mb1 = mb;
-        }
-        else if (atnr_global >= alook->mba[mb].a_end)
-        {
-            mb0 = mb;
-        }
-        else
-        {
-            break;
-        }
-        mb = ((mb0 + mb1 + 1)>>1);
-    }
-
-    *molb     = mb;
-    *molnr    = (atnr_global - a_start) / alook->mba[mb].na_mol;
-    *atnr_mol = atnr_global - a_start - (*molnr)*alook->mba[mb].na_mol;
-}
-
-void gmx_mtop_atominfo_global(const gmx_mtop_t *mtop, int atnr_global,
-                              char **atomname, int *resnr, char **resname)
-{
-    int             mb, a_start, a_end, maxresnr, at_loc;
-    t_atoms        *atoms = NULL;
-
-    if (atnr_global < 0 || atnr_global >= mtop->natoms)
-    {
-        gmx_fatal(FARGS, "gmx_mtop_atominfo_global was called with atnr_global=%d which is not in the atom range of this system (%d-%d)",
-                  atnr_global, 0, mtop->natoms-1);
-    }
-
-    mb       = -1;
-    a_end    = 0;
-    maxresnr = mtop->maxresnr;
-    do
-    {
-        if (mb >= 0)
-        {
-            /* cppcheck-suppress nullPointer #6330 will be fixed in cppcheck 1.73 */
-            if (atoms->nres <= mtop->maxres_renum)
-            {
-                /* Single residue molecule, keep counting */
-                /* cppcheck-suppress nullPointer #6330 will be fixed in cppcheck 1.73 */
-                maxresnr += mtop->molblock[mb].nmol*atoms->nres;
-            }
-        }
-        mb++;
-        atoms   = &mtop->moltype[mtop->molblock[mb].type].atoms;
-        a_start = a_end;
-        a_end   = a_start + mtop->molblock[mb].nmol*atoms->nr;
-    }
-    while (atnr_global >= a_end);
-
-    at_loc    = (atnr_global - a_start) % atoms->nr;
-    *atomname = *(atoms->atomname[at_loc]);
-    if (atoms->nres > mtop->maxres_renum)
-    {
-        *resnr = atoms->resinfo[atoms->atom[at_loc].resind].nr;
-    }
-    else
-    {
-        /* Single residue molecule, keep counting */
-        *resnr = maxresnr + 1 + (atnr_global - a_start)/atoms->nr*atoms->nres + atoms->atom[at_loc].resind;
-    }
-    *resname  = *(atoms->resinfo[atoms->atom[at_loc].resind].name);
-}
-
 typedef struct gmx_mtop_atomloop_all
 {
     const gmx_mtop_t *mtop;
@@ -472,7 +249,7 @@ static void gmx_mtop_atomloop_all_destroy(gmx_mtop_atomloop_all_t aloop)
 }
 
 gmx_bool gmx_mtop_atomloop_all_next(gmx_mtop_atomloop_all_t aloop,
-                                    int *at_global, t_atom **atom)
+                                    int *at_global, const t_atom **atom)
 {
     if (aloop == NULL)
     {
@@ -561,7 +338,7 @@ static void gmx_mtop_atomloop_block_destroy(gmx_mtop_atomloop_block_t aloop)
 }
 
 gmx_bool gmx_mtop_atomloop_block_next(gmx_mtop_atomloop_block_t aloop,
-                                      t_atom **atom, int *nmol)
+                                      const t_atom **atom, int *nmol)
 {
     if (aloop == NULL)
     {
@@ -779,13 +556,40 @@ static void atomcat(t_atoms *dest, t_atoms *src, int copies,
     int srcnr  = src->nr;
     int destnr = dest->nr;
 
+    if (dest->nr == 0)
+    {
+        dest->haveMass    = src->haveMass;
+        dest->haveType    = src->haveType;
+        dest->haveCharge  = src->haveCharge;
+        dest->haveBState  = src->haveBState;
+        dest->havePdbInfo = src->havePdbInfo;
+    }
+    else
+    {
+        dest->haveMass    = dest->haveMass    && src->haveMass;
+        dest->haveType    = dest->haveType    && src->haveType;
+        dest->haveCharge  = dest->haveCharge  && src->haveCharge;
+        dest->haveBState  = dest->haveBState  && src->haveBState;
+        dest->havePdbInfo = dest->havePdbInfo && src->havePdbInfo;
+    }
+
     if (srcnr)
     {
         size = destnr+copies*srcnr;
         srenew(dest->atom, size);
         srenew(dest->atomname, size);
-        srenew(dest->atomtype, size);
-        srenew(dest->atomtypeB, size);
+        if (dest->haveType)
+        {
+            srenew(dest->atomtype, size);
+            if (dest->haveBState)
+            {
+                srenew(dest->atomtypeB, size);
+            }
+        }
+        if (dest->havePdbInfo)
+        {
+            srenew(dest->pdbinfo, size);
+        }
     }
     if (src->nres)
     {
@@ -802,14 +606,25 @@ static void atomcat(t_atoms *dest, t_atoms *src, int copies,
 
     for (l = destnr, j = 0; (j < copies); j++, l += srcnr)
     {
-        memcpy((char *) &(dest->atomname[l]), (char *) &(src->atomname[0]),
-               (size_t)(srcnr*sizeof(src->atomname[0])));
-        memcpy((char *) &(dest->atomtype[l]), (char *) &(src->atomtype[0]),
-               (size_t)(srcnr*sizeof(src->atomtype[0])));
-        memcpy((char *) &(dest->atomtypeB[l]), (char *) &(src->atomtypeB[0]),
-               (size_t)(srcnr*sizeof(src->atomtypeB[0])));
         memcpy((char *) &(dest->atom[l]), (char *) &(src->atom[0]),
                (size_t)(srcnr*sizeof(src->atom[0])));
+        memcpy((char *) &(dest->atomname[l]), (char *) &(src->atomname[0]),
+               (size_t)(srcnr*sizeof(src->atomname[0])));
+        if (dest->haveType)
+        {
+            memcpy((char *) &(dest->atomtype[l]), (char *) &(src->atomtype[0]),
+                   (size_t)(srcnr*sizeof(src->atomtype[0])));
+            if (dest->haveBState)
+            {
+                memcpy((char *) &(dest->atomtypeB[l]), (char *) &(src->atomtypeB[0]),
+                       (size_t)(srcnr*sizeof(src->atomtypeB[0])));
+            }
+        }
+        if (dest->havePdbInfo)
+        {
+            memcpy((char *) &(dest->pdbinfo[l]), (char *) &(src->pdbinfo[0]),
+                   (size_t)(srcnr*sizeof(src->pdbinfo[0])));
+        }
     }
 
     /* Increment residue indices */
@@ -1032,7 +847,6 @@ static void gen_local_top(const gmx_mtop_t *mtop,
     real                   *qA, *qB;
     gmx_mtop_atomloop_all_t aloop;
     int                     ag;
-    t_atom                 *atom;
 
     top->atomtypes = mtop->atomtypes;
 
@@ -1125,6 +939,7 @@ static void gen_local_top(const gmx_mtop_t *mtop,
         snew(qA, mtop->natoms);
         snew(qB, mtop->natoms);
         aloop = gmx_mtop_atomloop_all_init(mtop);
+        const t_atom *atom;
         while (gmx_mtop_atomloop_all_next(aloop, &ag, &atom))
         {
             qA[ag] = atom->q;
@@ -1153,7 +968,7 @@ gmx_mtop_generate_local_top(const gmx_mtop_t *mtop,
     return top;
 }
 
-t_topology gmx_mtop_t_to_t_topology(gmx_mtop_t *mtop)
+t_topology gmx_mtop_t_to_t_topology(gmx_mtop_t *mtop, bool freeMTop)
 {
     int            mt, mb;
     gmx_localtop_t ltop;
@@ -1172,23 +987,23 @@ t_topology gmx_mtop_t_to_t_topology(gmx_mtop_t *mtop)
     top.bIntermolecularInteractions = mtop->bIntermolecularInteractions;
     top.symtab                      = mtop->symtab;
 
-    /* We only need to free the moltype and molblock data,
-     * all other pointers have been copied to top.
-     *
-     * Well, except for the group data, but we can't free those, because they
-     * are used somewhere even after a call to this function.
-     */
-    for (mt = 0; mt < mtop->nmoltype; mt++)
+    if (freeMTop)
     {
-        done_moltype(&mtop->moltype[mt]);
-    }
-    sfree(mtop->moltype);
+        // Free pointers that have not been copied to top.
+        for (mt = 0; mt < mtop->nmoltype; mt++)
+        {
+            done_moltype(&mtop->moltype[mt]);
+        }
+        sfree(mtop->moltype);
 
-    for (mb = 0; mb < mtop->nmolblock; mb++)
-    {
-        done_molblock(&mtop->molblock[mb]);
+        for (mb = 0; mb < mtop->nmolblock; mb++)
+        {
+            done_molblock(&mtop->molblock[mb]);
+        }
+        sfree(mtop->molblock);
+
+        done_gmx_groups_t(&mtop->groups);
     }
-    sfree(mtop->molblock);
 
     return top;
 }
@@ -1198,7 +1013,7 @@ std::vector<size_t> get_atom_index(const gmx_mtop_t *mtop)
 
     std::vector<size_t>       atom_index;
     gmx_mtop_atomloop_block_t aloopb = gmx_mtop_atomloop_block_init(mtop);
-    t_atom                   *atom;
+    const t_atom             *atom;
     int                       nmol, j = 0;
     while (gmx_mtop_atomloop_block_next(aloopb, &atom, &nmol))
     {
@@ -1210,3 +1025,33 @@ std::vector<size_t> get_atom_index(const gmx_mtop_t *mtop)
     }
     return atom_index;
 }
+
+void convertAtomsToMtop(t_symtab    *symtab,
+                        char       **name,
+                        t_atoms     *atoms,
+                        gmx_mtop_t  *mtop)
+{
+    mtop->symtab                 = *symtab;
+
+    mtop->name                   = name;
+
+    mtop->nmoltype               = 1;
+    // This snew clears all entries, we should replace it by an initializer
+    snew(mtop->moltype, mtop->nmoltype);
+    mtop->moltype[0].atoms       = *atoms;
+    init_block(&mtop->moltype[0].cgs);
+    init_blocka(&mtop->moltype[0].excls);
+
+    mtop->nmolblock              = 1;
+    // This snew clears all entries, we should replace it by an initializer
+    snew(mtop->molblock, mtop->nmolblock);
+    mtop->molblock[0].type       = 0;
+    mtop->molblock[0].nmol       = 1;
+    mtop->molblock[0].natoms_mol = atoms->nr;
+
+    mtop->bIntermolecularInteractions = FALSE;
+
+    mtop->natoms                 = atoms->nr;
+
+    gmx_mtop_finalize(mtop);
+}
index 3c01d34064eb05f1e187a8e4280145333330e2be..366cd13e9eaacb191ac982e41a97010eeb14d525 100644 (file)
 
 #include <vector>
 
+#include "gromacs/topology/topology.h"
 #include "gromacs/utility/basedefinitions.h"
+#include "gromacs/utility/gmxassert.h"
 
 struct gmx_localtop_t;
-struct gmx_moltype_t;
-struct gmx_mtop_t;
 struct t_atom;
 struct t_atoms;
 struct t_block;
 struct t_ilist;
-struct t_topology;
+struct t_symtab;
 
 /* Should be called after generating or reading mtop,
  * to set some compute intesive variables to avoid
@@ -70,62 +70,12 @@ gmx_mtop_count_atomtypes(const gmx_mtop_t *mtop, int state, int typecount[]);
 int
 ncg_mtop(const gmx_mtop_t *mtop);
 
+/* Returns the total number of residues in mtop. */
+int gmx_mtop_nres(const gmx_mtop_t *mtop);
+
 /* Removes the charge groups, i.e. makes single atom charge groups, in mtop */
 void gmx_mtop_remove_chargegroups(gmx_mtop_t *mtop);
 
-
-/* Abstract data type for looking up atoms by global atom number */
-typedef struct gmx_mtop_atomlookup *gmx_mtop_atomlookup_t;
-
-/* Initialize atom lookup by global atom number */
-gmx_mtop_atomlookup_t
-gmx_mtop_atomlookup_init(const gmx_mtop_t *mtop);
-
-/* As gmx_mtop_atomlookup_init, but optimized for atoms involved in settle */
-gmx_mtop_atomlookup_t
-gmx_mtop_atomlookup_settle_init(const gmx_mtop_t *mtop);
-
-/* Destroy a gmx_mtop_atomlookup_t data structure */
-void
-gmx_mtop_atomlookup_destroy(gmx_mtop_atomlookup_t alook);
-
-
-/* Returns a pointer to the t_atom struct belonging to atnr_global.
- * This can be an expensive operation, so if possible use
- * one of the atom loop constructs below.
- */
-void
-gmx_mtop_atomnr_to_atom(const gmx_mtop_atomlookup_t alook,
-                        int                         atnr_global,
-                        t_atom                    **atom);
-
-
-/* Returns a pointer to the molecule interaction array ilist_mol[F_NRE]
- * and the local atom number in the molecule belonging to atnr_global.
- */
-void
-gmx_mtop_atomnr_to_ilist(const gmx_mtop_atomlookup_t alook,
-                         int atnr_global,
-                         t_ilist **ilist_mol, int *atnr_offset);
-
-
-/* Returns the molecule block index
- * and the molecule number in the block
- * and the atom number offset for the atom indices in moltype
- * belonging to atnr_global.
- */
-void
-gmx_mtop_atomnr_to_molblock_ind(const gmx_mtop_atomlookup_t alook,
-                                int atnr_global,
-                                int *molb, int *molnr, int *atnr_mol);
-
-
-/* Returns atom name, global resnr and residue name  of atom atnr_global */
-void
-gmx_mtop_atominfo_global(const gmx_mtop_t *mtop, int atnr_global,
-                         char **atomname, int *resnr, char **resname);
-
-
 /* Abstract type for atom loop over all atoms */
 typedef struct gmx_mtop_atomloop_all *gmx_mtop_atomloop_all_t;
 
@@ -153,7 +103,7 @@ gmx_mtop_atomloop_all_init(const gmx_mtop_t *mtop);
  */
 gmx_bool
 gmx_mtop_atomloop_all_next(gmx_mtop_atomloop_all_t aloop,
-                           int *at_global, t_atom **atom);
+                           int *at_global, const t_atom **atom);
 
 /* Return the atomname, the residue number and residue name
  * of the current atom in the loop.
@@ -193,7 +143,7 @@ gmx_mtop_atomloop_block_init(const gmx_mtop_t *mtop);
  */
 gmx_bool
 gmx_mtop_atomloop_block_next(gmx_mtop_atomloop_block_t aloop,
-                             t_atom **atom, int *nmol);
+                             const t_atom **atom, int *nmol);
 
 
 /* Abstract type for ilist loop over all ilists */
@@ -253,7 +203,7 @@ gmx_mtop_global_atoms(const gmx_mtop_t *mtop);
 
 
 /* Generate a 'local' topology for the whole system.
- * When feeEnergyInteractionsAtEnd == true, the free energy interactions will
+ * When freeEnergyInteractionsAtEnd == true, the free energy interactions will
  * be sorted to the end.
  */
 gmx_localtop_t *
@@ -261,10 +211,14 @@ gmx_mtop_generate_local_top(const gmx_mtop_t *mtop, bool freeEnergyInteractionsA
 
 
 /* Converts a gmx_mtop_t struct to t_topology.
- * All memory relating only to mtop will be freed.
+ *
+ * If freeMTop == true, memory related to mtop will be freed so that done_top()
+ * on the result value will free all memory.
+ * If freeMTop == false, mtop and the return value will share some of their
+ * memory, and there is currently no way to consistently free all the memory.
  */
 t_topology
-gmx_mtop_t_to_t_topology(gmx_mtop_t *mtop);
+gmx_mtop_t_to_t_topology(gmx_mtop_t *mtop, bool freeMTop);
 
 /*! \brief Get vector of atoms indices from topology
  *
@@ -275,4 +229,20 @@ gmx_mtop_t_to_t_topology(gmx_mtop_t *mtop);
  */
 std::vector<size_t> get_atom_index(const gmx_mtop_t *mtop);
 
+/*! \brief Converts a t_atoms struct to an mtop struct
+ *
+ * All pointers contained in \p atoms will be copied into \p mtop.
+ * Note that this will produce one moleculetype encompassing the whole system.
+ *
+ * \param[in]  symtab  The symbol table
+ * \param[in]  name    Pointer to the name for the topology
+ * \param[in]  atoms   The atoms to convert
+ * \param[out] mtop    The molecular topology output containing atoms.
+ */
+void
+convertAtomsToMtop(t_symtab    *symtab,
+                   char       **name,
+                   t_atoms     *atoms,
+                   gmx_mtop_t  *mtop);
+
 #endif
index 235863d7f4c30b2be1a877b68a8e5c9fb8d181d8..5d3c5c30c5bb3f9517a765c9707de93ff946c870 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -57,6 +57,9 @@ static char *trim_string(const char *s, char *out, int maxlen)
  * Returns a pointer to a static area which contains a copy
  * of s without leading or trailing spaces. Strings are
  * truncated to BUFSIZE positions.
+ *
+ * TODO This partially duplicates code in trim(), but perhaps
+ * replacing symtab with a std::map is a better fix.
  */
 {
     int len, i;
@@ -67,7 +70,7 @@ static char *trim_string(const char *s, char *out, int maxlen)
                   s, strlen(s), maxlen-1);
     }
 
-    for (; (*s) && ((*s) == ' '); s++)
+    for (; (*s) == ' '; s++)
     {
         ;
     }
index c2d0f602ccce840000bd45c4c8113cf067deebca..f113900e1364fc4a16b534b5de5581b7234588ec 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 #include <algorithm>
 
 #include "gromacs/math/vecdump.h"
+#include "gromacs/topology/atoms.h"
+#include "gromacs/topology/idef.h"
 #include "gromacs/topology/ifunc.h"
 #include "gromacs/topology/symtab.h"
+#include "gromacs/utility/compare.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/stringutil.h"
 #include "gromacs/utility/txtdump.h"
@@ -120,12 +123,30 @@ void done_molblock(gmx_molblock_t *molb)
     }
 }
 
-void done_mtop(gmx_mtop_t *mtop, gmx_bool bDoneSymtab)
+void done_gmx_groups_t(gmx_groups_t *g)
 {
-    if (bDoneSymtab)
+    int i;
+
+    for (i = 0; (i < egcNR); i++)
     {
-        done_symtab(&mtop->symtab);
+        if (NULL != g->grps[i].nm_ind)
+        {
+            sfree(g->grps[i].nm_ind);
+            g->grps[i].nm_ind = NULL;
+        }
+        if (NULL != g->grpnr[i])
+        {
+            sfree(g->grpnr[i]);
+            g->grpnr[i] = NULL;
+        }
     }
+    /* The contents of this array is in symtab, don't free it here */
+    sfree(g->grpname);
+}
+
+void done_mtop(gmx_mtop_t *mtop)
+{
+    done_symtab(&mtop->symtab);
 
     sfree(mtop->ffparams.functype);
     sfree(mtop->ffparams.iparams);
@@ -140,6 +161,8 @@ void done_mtop(gmx_mtop_t *mtop, gmx_bool bDoneSymtab)
         done_molblock(&mtop->molblock[i]);
     }
     sfree(mtop->molblock);
+    done_atomtypes(&mtop->atomtypes);
+    done_gmx_groups_t(&mtop->groups);
     done_block(&mtop->mols);
 }
 
@@ -165,6 +188,64 @@ void done_top(t_topology *top)
     done_blocka(&(top->excls));
 }
 
+void done_top_mtop(t_topology *top, gmx_mtop_t *mtop)
+{
+    if (mtop != nullptr)
+    {
+        if (top != nullptr)
+        {
+            for (int f = 0; f < F_NRE; ++f)
+            {
+                sfree(top->idef.il[f].iatoms);
+                top->idef.il[f].iatoms = NULL;
+                top->idef.il[f].nalloc = 0;
+            }
+            done_atom(&top->atoms);
+            done_block(&top->cgs);
+            done_blocka(&top->excls);
+            done_symtab(&top->symtab);
+            open_symtab(&mtop->symtab);
+        }
+        done_mtop(mtop);
+    }
+}
+
+bool gmx_mtop_has_masses(const gmx_mtop_t *mtop)
+{
+    if (mtop == nullptr)
+    {
+        return false;
+    }
+    return mtop->nmoltype == 0 || mtop->moltype[0].atoms.haveMass;
+}
+
+bool gmx_mtop_has_charges(const gmx_mtop_t *mtop)
+{
+    if (mtop == nullptr)
+    {
+        return false;
+    }
+    return mtop->nmoltype == 0 || mtop->moltype[0].atoms.haveCharge;
+}
+
+bool gmx_mtop_has_atomtypes(const gmx_mtop_t *mtop)
+{
+    if (mtop == nullptr)
+    {
+        return false;
+    }
+    return mtop->nmoltype == 0 || mtop->moltype[0].atoms.haveType;
+}
+
+bool gmx_mtop_has_pdbinfo(const gmx_mtop_t *mtop)
+{
+    if (mtop == nullptr)
+    {
+        return false;
+    }
+    return mtop->nmoltype == 0 || mtop->moltype[0].atoms.havePdbInfo;
+}
+
 static void pr_grps(FILE *fp, const char *title, const t_grps grps[], char **grpname[])
 {
     int i, j;
@@ -236,7 +317,7 @@ static void pr_groups(FILE *fp, int indent,
 static void pr_moltype(FILE *fp, int indent, const char *title,
                        const gmx_moltype_t *molt, int n,
                        const gmx_ffparams_t *ffparams,
-                       gmx_bool bShowNumbers)
+                       gmx_bool bShowNumbers, gmx_bool bShowParameters)
 {
     int j;
 
@@ -249,7 +330,8 @@ static void pr_moltype(FILE *fp, int indent, const char *title,
     for (j = 0; (j < F_NRE); j++)
     {
         pr_ilist(fp, indent, interaction_function[j].longname,
-                 ffparams->functype, &molt->ilist[j], bShowNumbers);
+                 ffparams->functype, &molt->ilist[j],
+                 bShowNumbers, bShowParameters, ffparams->iparams);
     }
 }
 
@@ -276,7 +358,7 @@ static void pr_molblock(FILE *fp, int indent, const char *title,
 }
 
 void pr_mtop(FILE *fp, int indent, const char *title, const gmx_mtop_t *mtop,
-             gmx_bool bShowNumbers)
+             gmx_bool bShowNumbers, gmx_bool bShowParameters)
 {
     int mt, mb, j;
 
@@ -299,7 +381,8 @@ void pr_mtop(FILE *fp, int indent, const char *title, const gmx_mtop_t *mtop,
             {
                 pr_ilist(fp, indent, interaction_function[j].longname,
                          mtop->ffparams.functype,
-                         &mtop->intermolecular_ilist[j], bShowNumbers);
+                         &mtop->intermolecular_ilist[j],
+                         bShowNumbers, bShowParameters, mtop->ffparams.iparams);
             }
         }
         pr_ffparams(fp, indent, "ffparams", &(mtop->ffparams), bShowNumbers);
@@ -307,13 +390,14 @@ void pr_mtop(FILE *fp, int indent, const char *title, const gmx_mtop_t *mtop,
         for (mt = 0; mt < mtop->nmoltype; mt++)
         {
             pr_moltype(fp, indent, "moltype", &mtop->moltype[mt], mt,
-                       &mtop->ffparams, bShowNumbers);
+                       &mtop->ffparams, bShowNumbers, bShowParameters);
         }
         pr_groups(fp, indent, &mtop->groups, bShowNumbers);
     }
 }
 
-void pr_top(FILE *fp, int indent, const char *title, const t_topology *top, gmx_bool bShowNumbers)
+void pr_top(FILE *fp, int indent, const char *title, const t_topology *top,
+            gmx_bool bShowNumbers, gmx_bool bShowParameters)
 {
     if (available(fp, top, indent, title))
     {
@@ -327,6 +411,216 @@ void pr_top(FILE *fp, int indent, const char *title, const t_topology *top, gmx_
         pr_str(fp, indent, "bIntermolecularInteractions",
                gmx::boolToString(top->bIntermolecularInteractions));
         pr_blocka(fp, indent, "excls", &top->excls, bShowNumbers);
-        pr_idef(fp, indent, "idef", &top->idef, bShowNumbers);
+        pr_idef(fp, indent, "idef", &top->idef, bShowNumbers, bShowParameters);
+    }
+}
+
+static void cmp_ilist(FILE *fp, int ftype, const t_ilist *il1, const t_ilist *il2)
+{
+    int  i;
+    char buf[256];
+
+    fprintf(fp, "comparing ilist %s\n", interaction_function[ftype].name);
+    sprintf(buf, "%s->nr", interaction_function[ftype].name);
+    cmp_int(fp, buf, -1, il1->nr, il2->nr);
+    sprintf(buf, "%s->iatoms", interaction_function[ftype].name);
+    if (((il1->nr > 0) && (!il1->iatoms)) ||
+        ((il2->nr > 0) && (!il2->iatoms)) ||
+        ((il1->nr != il2->nr)))
+    {
+        fprintf(fp, "Comparing radically different topologies - %s is different\n",
+                buf);
+    }
+    else
+    {
+        for (i = 0; (i < il1->nr); i++)
+        {
+            cmp_int(fp, buf, i, il1->iatoms[i], il2->iatoms[i]);
+        }
+    }
+}
+
+static void cmp_iparm(FILE *fp, const char *s, t_functype ft,
+                      const t_iparams &ip1, const t_iparams &ip2, real ftol, real abstol)
+{
+    int      i;
+    gmx_bool bDiff;
+
+    bDiff = FALSE;
+    for (i = 0; i < MAXFORCEPARAM && !bDiff; i++)
+    {
+        bDiff = !equal_real(ip1.generic.buf[i], ip2.generic.buf[i], ftol, abstol);
+    }
+    if (bDiff)
+    {
+        fprintf(fp, "%s1: ", s);
+        pr_iparams(fp, ft, &ip1);
+        fprintf(fp, "%s2: ", s);
+        pr_iparams(fp, ft, &ip2);
+    }
+}
+
+static void cmp_iparm_AB(FILE *fp, const char *s, t_functype ft,
+                         const t_iparams &ip1, real ftol, real abstol)
+{
+    int      nrfpA, nrfpB, p0, i;
+    gmx_bool bDiff;
+
+    /* Normally the first parameter is perturbable */
+    p0    = 0;
+    nrfpA = interaction_function[ft].nrfpA;
+    nrfpB = interaction_function[ft].nrfpB;
+    if (ft == F_PDIHS)
+    {
+        nrfpB = 2;
+    }
+    else if (interaction_function[ft].flags & IF_TABULATED)
+    {
+        /* For tabulated interactions only the second parameter is perturbable */
+        p0    = 1;
+        nrfpB = 1;
+    }
+    bDiff = FALSE;
+    for (i = 0; i < nrfpB && !bDiff; i++)
+    {
+        bDiff = !equal_real(ip1.generic.buf[p0+i], ip1.generic.buf[nrfpA+i], ftol, abstol);
+    }
+    if (bDiff)
+    {
+        fprintf(fp, "%s: ", s);
+        pr_iparams(fp, ft, &ip1);
+    }
+}
+
+static void cmp_cmap(FILE *fp, const gmx_cmap_t *cmap1, const gmx_cmap_t *cmap2, real ftol, real abstol)
+{
+    cmp_int(fp, "cmap ngrid", -1, cmap1->ngrid, cmap2->ngrid);
+    cmp_int(fp, "cmap grid_spacing", -1, cmap1->grid_spacing, cmap2->grid_spacing);
+    if (cmap1->ngrid == cmap2->ngrid &&
+        cmap1->grid_spacing == cmap2->grid_spacing)
+    {
+        int g;
+
+        for (g = 0; g < cmap1->ngrid; g++)
+        {
+            int i;
+
+            fprintf(fp, "comparing cmap %d\n", g);
+
+            for (i = 0; i < 4*cmap1->grid_spacing*cmap1->grid_spacing; i++)
+            {
+                cmp_real(fp, "", i, cmap1->cmapdata[g].cmap[i], cmap2->cmapdata[g].cmap[i], ftol, abstol);
+            }
+        }
+    }
+}
+
+static void cmp_idef(FILE *fp, const t_idef *id1, const t_idef *id2, real ftol, real abstol)
+{
+    int  i;
+    char buf1[64], buf2[64];
+
+    fprintf(fp, "comparing idef\n");
+    if (id2)
+    {
+        cmp_int(fp, "idef->ntypes", -1, id1->ntypes, id2->ntypes);
+        cmp_int(fp, "idef->atnr",  -1, id1->atnr, id2->atnr);
+        for (i = 0; (i < std::min(id1->ntypes, id2->ntypes)); i++)
+        {
+            sprintf(buf1, "idef->functype[%d]", i);
+            sprintf(buf2, "idef->iparam[%d]", i);
+            cmp_int(fp, buf1, i, (int)id1->functype[i], (int)id2->functype[i]);
+            cmp_iparm(fp, buf2, id1->functype[i],
+                      id1->iparams[i], id2->iparams[i], ftol, abstol);
+        }
+        cmp_real(fp, "fudgeQQ", -1, id1->fudgeQQ, id2->fudgeQQ, ftol, abstol);
+        cmp_cmap(fp, &id1->cmap_grid, &id2->cmap_grid, ftol, abstol);
+        for (i = 0; (i < F_NRE); i++)
+        {
+            cmp_ilist(fp, i, &(id1->il[i]), &(id2->il[i]));
+        }
+    }
+    else
+    {
+        for (i = 0; (i < id1->ntypes); i++)
+        {
+            cmp_iparm_AB(fp, "idef->iparam", id1->functype[i], id1->iparams[i], ftol, abstol);
+        }
+    }
+}
+
+static void cmp_block(FILE *fp, const t_block *b1, const t_block *b2, const char *s)
+{
+    char buf[32];
+
+    fprintf(fp, "comparing block %s\n", s);
+    sprintf(buf, "%s.nr", s);
+    cmp_int(fp, buf, -1, b1->nr, b2->nr);
+}
+
+static void cmp_blocka(FILE *fp, const t_blocka *b1, const t_blocka *b2, const char *s)
+{
+    char buf[32];
+
+    fprintf(fp, "comparing blocka %s\n", s);
+    sprintf(buf, "%s.nr", s);
+    cmp_int(fp, buf, -1, b1->nr, b2->nr);
+    sprintf(buf, "%s.nra", s);
+    cmp_int(fp, buf, -1, b1->nra, b2->nra);
+}
+
+void cmp_top(FILE *fp, const t_topology *t1, const t_topology *t2, real ftol, real abstol)
+{
+    fprintf(fp, "comparing top\n");
+    if (t2)
+    {
+        cmp_idef(fp, &(t1->idef), &(t2->idef), ftol, abstol);
+        cmp_atoms(fp, &(t1->atoms), &(t2->atoms), ftol, abstol);
+        cmp_block(fp, &t1->cgs, &t2->cgs, "cgs");
+        cmp_block(fp, &t1->mols, &t2->mols, "mols");
+        cmp_bool(fp, "bIntermolecularInteractions", -1, t1->bIntermolecularInteractions, t2->bIntermolecularInteractions);
+        cmp_blocka(fp, &t1->excls, &t2->excls, "excls");
+    }
+    else
+    {
+        cmp_idef(fp, &(t1->idef), NULL, ftol, abstol);
+        cmp_atoms(fp, &(t1->atoms), NULL, ftol, abstol);
+    }
+}
+
+void cmp_groups(FILE *fp, const gmx_groups_t *g0, const gmx_groups_t *g1,
+                int natoms0, int natoms1)
+{
+    int  i, j;
+    char buf[32];
+
+    fprintf(fp, "comparing groups\n");
+
+    for (i = 0; i < egcNR; i++)
+    {
+        sprintf(buf, "grps[%d].nr", i);
+        cmp_int(fp, buf, -1, g0->grps[i].nr, g1->grps[i].nr);
+        if (g0->grps[i].nr == g1->grps[i].nr)
+        {
+            for (j = 0; j < g0->grps[i].nr; j++)
+            {
+                sprintf(buf, "grps[%d].name[%d]", i, j);
+                cmp_str(fp, buf, -1,
+                        *g0->grpname[g0->grps[i].nm_ind[j]],
+                        *g1->grpname[g1->grps[i].nm_ind[j]]);
+            }
+        }
+        cmp_int(fp, "ngrpnr", i, g0->ngrpnr[i], g1->ngrpnr[i]);
+        if (g0->ngrpnr[i] == g1->ngrpnr[i] && natoms0 == natoms1 &&
+            (g0->grpnr[i] != NULL || g1->grpnr[i] != NULL))
+        {
+            for (j = 0; j < natoms0; j++)
+            {
+                cmp_int(fp, gtypes[i], j, ggrpnr(g0, i, j), ggrpnr(g1, i, j));
+            }
+        }
     }
+    /* We have compared the names in the groups lists,
+     * so we can skip the grpname list comparison.
+     */
 }
index 5d3426ccaffa827e17fee744425b31564e3f7b91..89c40bfc0816819247c06a9e7423b45ee58c781e 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2011,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2011,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 #include "gromacs/topology/idef.h"
 #include "gromacs/topology/symtab.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 enum {
     egcTC,    egcENER,   egcACC, egcFREEZE,
     egcUser1, egcUser2,  egcVCM, egcCompressedX,
@@ -67,15 +63,22 @@ typedef struct gmx_moltype_t
     t_blocka        excls;        /* The exclusions                       */
 } gmx_moltype_t;
 
+/*! \brief Block of molecules of the same type, used in gmx_mtop_t */
 typedef struct gmx_molblock_t
 {
-    int            type;        /* The molcule type index in mtop.moltype */
-    int            nmol;        /* The number of molecules in this block  */
-    int            natoms_mol;  /* The number of atoms in one molecule    */
-    int            nposres_xA;  /* The number of posres coords for top A  */
-    rvec          *posres_xA;   /* The posres coords for top A            */
-    int            nposres_xB;  /* The number of posres coords for top B  */
-    rvec          *posres_xB;   /* The posres coords for top B            */
+    int     type;               /**< The molecule type index in mtop.moltype  */
+    int     nmol;               /**< The number of molecules in this block    */
+    int     nposres_xA;         /**< The number of posres coords for top A    */
+    rvec   *posres_xA;          /**< Position restraint coordinates for top A */
+    int     nposres_xB;         /**< The number of posres coords for top B    */
+    rvec   *posres_xB;          /**< Position restraint coordinates for top B */
+
+    /* Convenience information, derived from other gmx_mtop_t contents     */
+    int     natoms_mol;         /**< The number of atoms in one molecule      */
+    int     globalAtomStart;    /**< Global atom index of the first atom in the block */
+    int     globalAtomEnd;      /**< Global atom index + 1 of the last atom in the block */
+    int     globalResidueStart; /**< Global residue index of the first residue in the block */
+    int     residueNumberStart; /**< Residue numbers start from this value if the number of residues per molecule is <= maxres_renum */
 } gmx_molblock_t;
 
 typedef struct gmx_groups_t
@@ -144,18 +147,25 @@ void init_mtop(gmx_mtop_t *mtop);
 void init_top(t_topology *top);
 void done_moltype(gmx_moltype_t *molt);
 void done_molblock(gmx_molblock_t *molb);
-void done_mtop(gmx_mtop_t *mtop, gmx_bool bDoneSymtab);
+void done_gmx_groups_t(gmx_groups_t *g);
+void done_mtop(gmx_mtop_t *mtop);
 void done_top(t_topology *top);
+// Frees both t_topology and gmx_mtop_t when the former has been created from
+// the latter.
+void done_top_mtop(t_topology *top, gmx_mtop_t *mtop);
 
-t_atoms *mtop2atoms(gmx_mtop_t *mtop);
-/* generate a t_atoms struct for the system from gmx_mtop_t */
+bool gmx_mtop_has_masses(const gmx_mtop_t *mtop);
+bool gmx_mtop_has_charges(const gmx_mtop_t *mtop);
+bool gmx_mtop_has_atomtypes(const gmx_mtop_t *mtop);
+bool gmx_mtop_has_pdbinfo(const gmx_mtop_t *mtop);
 
 void pr_mtop(FILE *fp, int indent, const char *title, const gmx_mtop_t *mtop,
-             gmx_bool bShowNumbers);
-void pr_top(FILE *fp, int indent, const char *title, const t_topology *top, gmx_bool bShowNumbers);
+             gmx_bool bShowNumbers, gmx_bool bShowParameters);
+void pr_top(FILE *fp, int indent, const char *title, const t_topology *top,
+            gmx_bool bShowNumbers, gmx_bool bShowParameters);
 
-#ifdef __cplusplus
-}
-#endif
+void cmp_top(FILE *fp, const t_topology *t1, const t_topology *t2, real ftol, real abstol);
+void cmp_groups(FILE *fp, const gmx_groups_t *g0, const gmx_groups_t *g1,
+                int natoms0, int natoms1);
 
 #endif
index 3bcbd3ced459f4c8407962817d14c524b37f593b..e6f935930714e163a23c2dab294c4eb239263bbc 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2015, by the GROMACS development team, led by
+# Copyright (c) 2015,2016, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
 # To help us fund GROMACS development, we humbly ask that you cite
 # the research papers on the package. Check out http://www.gromacs.org.
 
+gmx_add_libgromacs_sources(
+    trajectoryframe.cpp
+    )
+
 gmx_install_headers(
     energy.h
     trajectoryframe.h
     )
-
diff --git a/src/gromacs/trajectory/trajectoryframe.cpp b/src/gromacs/trajectory/trajectoryframe.cpp
new file mode 100644 (file)
index 0000000..c26d39a
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+#include "gmxpre.h"
+
+#include "trajectoryframe.h"
+
+#include <cstdio>
+
+#include <algorithm>
+
+#include "gromacs/math/veccompare.h"
+#include "gromacs/topology/atoms.h"
+#include "gromacs/utility/compare.h"
+
+void comp_frame(FILE *fp, t_trxframe *fr1, t_trxframe *fr2,
+                gmx_bool bRMSD, real ftol, real abstol)
+{
+    fprintf(fp, "\n");
+    cmp_int(fp, "not_ok", -1, fr1->not_ok, fr2->not_ok);
+    cmp_int(fp, "natoms", -1, fr1->natoms, fr2->natoms);
+    if (cmp_bool(fp, "bTitle", -1, fr1->bTitle, fr2->bTitle))
+    {
+        cmp_str(fp, "title", -1, fr1->title, fr2->title);
+    }
+    if (cmp_bool(fp, "bStep", -1, fr1->bStep, fr2->bStep))
+    {
+        cmp_int(fp, "step", -1, fr1->step, fr2->step);
+    }
+    cmp_int(fp, "step", -1, fr1->step, fr2->step);
+    if (cmp_bool(fp, "bTime", -1, fr1->bTime, fr2->bTime))
+    {
+        cmp_real(fp, "time", -1, fr1->time, fr2->time, ftol, abstol);
+    }
+    if (cmp_bool(fp, "bLambda", -1, fr1->bLambda, fr2->bLambda))
+    {
+        cmp_real(fp, "lambda", -1, fr1->lambda, fr2->lambda, ftol, abstol);
+    }
+    if (cmp_bool(fp, "bAtoms", -1, fr1->bAtoms, fr2->bAtoms))
+    {
+        cmp_atoms(fp, fr1->atoms, fr2->atoms, ftol, abstol);
+    }
+    if (cmp_bool(fp, "bPrec", -1, fr1->bPrec, fr2->bPrec))
+    {
+        cmp_real(fp, "prec", -1, fr1->prec, fr2->prec, ftol, abstol);
+    }
+    if (cmp_bool(fp, "bX", -1, fr1->bX, fr2->bX))
+    {
+        cmp_rvecs(fp, "x", std::min(fr1->natoms, fr2->natoms), fr1->x, fr2->x, bRMSD, ftol, abstol);
+    }
+    if (cmp_bool(fp, "bV", -1, fr1->bV, fr2->bV))
+    {
+        cmp_rvecs(fp, "v", std::min(fr1->natoms, fr2->natoms), fr1->v, fr2->v, bRMSD, ftol, abstol);
+    }
+    if (cmp_bool(fp, "bF", -1, fr1->bF, fr2->bF))
+    {
+        cmp_rvecs(fp, "f", std::min(fr1->natoms, fr2->natoms), fr1->f, fr2->f, bRMSD, ftol, abstol);
+    }
+    if (cmp_bool(fp, "bBox", -1, fr1->bBox, fr2->bBox))
+    {
+        cmp_rvecs(fp, "box", 3, fr1->box, fr2->box, FALSE, ftol, abstol);
+    }
+}
index f329947fe6b987731d592bb116722865b64efdec..9b65402684304e10869a5996a1d4ac28926539de 100644 (file)
  * Do not try to use a pointer when its gmx_bool is FALSE, as memory might
  * not be allocated.
  */
-
 #ifndef GMX_TRAJECTORY_TRX_H
 #define GMX_TRAJECTORY_TRX_H
 
+#include <cstdio>
+
 #include "gromacs/math/vectypes.h"
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
@@ -82,4 +83,7 @@ typedef struct t_trxframe
     int            *index;     /* atom indices of contained coordinates */
 } t_trxframe;
 
+void comp_frame(FILE *fp, t_trxframe *fr1, t_trxframe *fr2,
+                gmx_bool bRMSD, real ftol, real abstol);
+
 #endif
index fab17441dd41c7107b98fd58a0a5314703d86130..11b2fc2b14b3be6d2d58671a4dfb5a88848c6156 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -350,7 +350,7 @@ void TrajectoryAnalysisModule::registerBasicDataset(AbstractAnalysisData *data,
     GMX_RELEASE_ASSERT(impl_->datasets_.find(name) == impl_->datasets_.end(),
                        "Duplicate data set name registered");
     impl_->datasets_[name] = data;
-    impl_->datasetNames_.push_back(name);
+    impl_->datasetNames_.emplace_back(name);
 }
 
 
index e8559c04d20c3a9d4e1209f775282b85320d6ef4..98759771d41fb60d9ed2de8bfb1c3be285b85287 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -46,6 +46,7 @@
 #include "gromacs/commandline/cmdlineoptionsmodule.h"
 #include "gromacs/fileio/trxio.h"
 #include "gromacs/math/vec.h"
+#include "gromacs/topology/mtop_util.h"
 #include "gromacs/topology/topology.h"
 #include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/exceptions.h"
@@ -185,7 +186,7 @@ TrajectoryAnalysisSettings::setHelpText(const ConstArrayRef<const char *> &help)
  */
 
 TopologyInformation::TopologyInformation()
-    : top_(NULL), bTop_(false), xtop_(NULL), ePBC_(-1)
+    : mtop_(NULL), top_(NULL), bTop_(false), xtop_(NULL), ePBC_(-1)
 {
     clear_mat(boxtop_);
 }
@@ -193,12 +194,21 @@ TopologyInformation::TopologyInformation()
 
 TopologyInformation::~TopologyInformation()
 {
-    if (top_)
+    done_top_mtop(top_, mtop_);
+    sfree(mtop_);
+    sfree(top_);
+    sfree(xtop_);
+}
+
+
+t_topology *TopologyInformation::topology() const
+{
+    if (top_ == nullptr && mtop_ != nullptr)
     {
-        done_top(top_);
-        sfree(top_);
+        snew(top_, 1);
+        *top_ = gmx_mtop_t_to_t_topology(mtop_, false);
     }
-    sfree(xtop_);
+    return top_;
 }
 
 
index 6a34742ec1f9ae039c8ad22e19f80c2807a6caef..0873d8a5a696ed5992f2e2d4c1222904716c6aeb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -49,6 +49,7 @@
 #include "gromacs/options/timeunitmanager.h"
 #include "gromacs/utility/classhelpers.h"
 
+struct gmx_mtop_t;
 struct t_topology;
 
 namespace gmx
@@ -253,11 +254,13 @@ class TopologyInformation
 {
     public:
         //! Returns true if a topology file was loaded.
-        bool hasTopology() const { return top_ != NULL; }
+        bool hasTopology() const { return mtop_ != NULL; }
         //! Returns true if a full topology file was loaded.
         bool hasFullTopology() const { return bTop_; }
         //! Returns the loaded topology, or NULL if not loaded.
-        t_topology *topology() const { return top_; }
+        const gmx_mtop_t *mtop() const { return mtop_; }
+        //! Returns the loaded topology, or NULL if not loaded.
+        t_topology *topology() const;
         //! Returns the ePBC field from the topology.
         int ePBC() const { return ePBC_; }
         /*! \brief
@@ -281,8 +284,10 @@ class TopologyInformation
         TopologyInformation();
         ~TopologyInformation();
 
+        gmx_mtop_t          *mtop_;
         //! The topology structure, or NULL if no topology loaded.
-        t_topology          *top_;
+        // TODO: Replace fully with mtop.
+        mutable t_topology  *top_;
         //! true if full tpx file was loaded, false otherwise.
         bool                 bTop_;
         //! Coordinates from the topology (can be NULL).
index 7fc2601f6df577ae02d2d9245c960d2316655d96..94724722169cc6b343f9665d2fa3c676c964e9f5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -53,6 +53,7 @@
 #include "modules/rdf.h"
 #include "modules/sasa.h"
 #include "modules/select.h"
+#include "modules/trajectory.h"
 
 namespace gmx
 {
@@ -96,6 +97,7 @@ void registerTrajectoryAnalysisModules(CommandLineModuleManager *manager)
     registerModule<RdfInfo>(manager, group);
     registerModule<SasaInfo>(manager, group);
     registerModule<SelectInfo>(manager, group);
+    registerModule<TrajectoryInfo>(manager, group);
 }
 //! \endcond
 
index df8fe70a27ba45860eae26a7c236bc304654b987..a3988d03e3d7ef80536adc371bec1c0cc2b1e55b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -345,7 +345,7 @@ Distance::analyzeFrame(int frnr, const t_trxframe &fr, t_pbc *pbc,
             real dist     = norm(dx);
             bool bPresent = p1.selected() && p2.selected();
             distHandle.setPoint(n, dist, bPresent);
-            xyzHandle.setPoints(n*3, 3, dx);
+            xyzHandle.setPoints(n*3, 3, dx, bPresent);
         }
     }
     distHandle.finishFrame();
index 3091cb4451f299c3891add4012e9a8315eecc36d..72f7417944a668ea8f288687e54a364af529ae7b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -238,7 +238,7 @@ PairDistance::initOptions(IOptionsContainer *options, TrajectoryAnalysisSettings
 }
 
 //! Helper function to initialize the grouping for a selection.
-int initSelectionGroups(Selection *sel, t_topology *top, int type)
+int initSelectionGroups(Selection *sel, const gmx_mtop_t *top, int type)
 {
     e_index_t indexType = INDEX_UNKNOWN;
     switch (type)
@@ -256,14 +256,14 @@ void
 PairDistance::initAnalysis(const TrajectoryAnalysisSettings &settings,
                            const TopologyInformation        &top)
 {
-    refGroupCount_ = initSelectionGroups(&refSel_, top.topology(), refGroupType_);
+    refGroupCount_ = initSelectionGroups(&refSel_, top.mtop(), refGroupType_);
 
     maxGroupCount_ = 0;
     distances_.setDataSetCount(sel_.size());
     for (size_t i = 0; i < sel_.size(); ++i)
     {
         const int selGroupCount
-            = initSelectionGroups(&sel_[i], top.topology(), selGroupType_);
+            = initSelectionGroups(&sel_[i], top.mtop(), selGroupType_);
         const int columnCount = refGroupCount_ * selGroupCount;
         maxGroupCount_ = std::max(maxGroupCount_, columnCount);
         distances_.setColumnCount(i, columnCount);
index 958a67b9c6cb071946a4882bf46400af88e29aeb..664682e0abeaecb92e262eef4ac6f76b5a7369e4 100644 (file)
@@ -358,7 +358,7 @@ Rdf::initAnalysis(const TrajectoryAnalysisSettings &settings,
             GMX_THROW(InconsistentInputError("-surf only works with -ref that consists of atoms"));
         }
         const e_index_t type = (surface_ == SurfaceType_Molecule ? INDEX_MOL : INDEX_RES);
-        surfaceGroupCount_ = refSel_.initOriginalIdsToGroup(top.topology(), type);
+        surfaceGroupCount_ = refSel_.initOriginalIdsToGroup(top.mtop(), type);
     }
 
     if (bExclusions_)
index bd440203e22708e8e4a20cd833bab1ae9150305d..20cbc4ab4c7d649a54274d8d7a139b36739bf3e7 100644 (file)
@@ -555,7 +555,7 @@ Sasa::initAnalysis(const TrajectoryAnalysisSettings &settings,
         dgsFactor_.reserve(surfaceSel_.posCount());
     }
 
-    const int resCount = surfaceSel_.initOriginalIdsToGroup(top_, INDEX_RES);
+    const int resCount = surfaceSel_.initOriginalIdsToGroup(top.mtop(), INDEX_RES);
 
     // TODO: Not exception-safe, but nice solution would be to have a C++
     // atom properties class...
index 44b3db90f8d63a8d4706f4ff5036ec60e426b1e0..4c6ad4dd9587103769005f0f51413fad345174c9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -168,7 +168,7 @@ void IndexFileWriterModule::addGroup(const std::string &name, bool bDynamic)
 {
     std::string newName(name);
     std::replace(newName.begin(), newName.end(), ' ', '_');
-    groups_.push_back(GroupInfo(newName, bDynamic));
+    groups_.emplace_back(newName, bDynamic);
 }
 
 
@@ -293,7 +293,6 @@ class Select : public TrajectoryAnalysisModule
 
     private:
         SelectionList                       sel_;
-        SelectionOptionInfo                *selOpt_;
 
         std::string                         fnSize_;
         std::string                         fnFrac_;
@@ -321,7 +320,7 @@ class Select : public TrajectoryAnalysisModule
 };
 
 Select::Select()
-    : selOpt_(NULL), bTotNorm_(false), bFracNorm_(false), bResInd_(false),
+    : bTotNorm_(false), bFracNorm_(false), bResInd_(false),
       bCumulativeLifetimes_(true), resNumberType_(ResidueNumbering_ByNumber),
       pdbAtoms_(PdbAtomsSelection_All), top_(NULL),
       occupancyModule_(new AnalysisDataAverageModule()),
@@ -351,11 +350,13 @@ Select::initOptions(IOptionsContainer *options, TrajectoryAnalysisSettings *sett
         "be combined with output from other programs and/or external",
         "analysis programs to calculate more complex things.",
         "For detailed help on the selection syntax, please use",
-        "[TT]gmx help selections[tt].[PAR]",
+        "[TT]gmx help selections[tt].",
+        "",
         "Any combination of the output options is possible, but note",
         "that [TT]-om[tt] only operates on the first selection.",
         "Also note that if you provide no output options, no output is",
-        "produced.[PAR]",
+        "produced.",
+        "",
         "With [TT]-os[tt], calculates the number of positions in each",
         "selection for each frame. With [TT]-norm[tt], the output is",
         "between 0 and 1 and describes the fraction from the maximum",
@@ -364,35 +365,42 @@ Select::initOptions(IOptionsContainer *options, TrajectoryAnalysisSettings *sett
         "RA residues). With [TT]-cfnorm[tt], the output is divided",
         "by the fraction covered by the selection.",
         "[TT]-norm[tt] and [TT]-cfnorm[tt] can be specified independently",
-        "of one another.[PAR]",
+        "of one another.",
+        "",
         "With [TT]-oc[tt], the fraction covered by each selection is",
-        "written out as a function of time.[PAR]",
+        "written out as a function of time.",
+        "",
         "With [TT]-oi[tt], the selected atoms/residues/molecules are",
         "written out as a function of time. In the output, the first",
         "column contains the frame time, the second contains the number",
         "of positions, followed by the atom/residue/molecule numbers.",
         "If more than one selection is specified, the size of the second",
         "group immediately follows the last number of the first group",
-        "and so on.[PAR]",
+        "and so on.",
+        "",
         "With [TT]-on[tt], the selected atoms are written as a index file",
         "compatible with [TT]make_ndx[tt] and the analyzing tools. Each selection",
         "is written as a selection group and for dynamic selections a",
-        "group is written for each frame.[PAR]",
+        "group is written for each frame.",
+        "",
         "For residue numbers, the output of [TT]-oi[tt] can be controlled",
         "with [TT]-resnr[tt]: [TT]number[tt] (default) prints the residue",
         "numbers as they appear in the input file, while [TT]index[tt] prints",
         "unique numbers assigned to the residues in the order they appear",
         "in the input file, starting with 1. The former is more intuitive,",
         "but if the input contains multiple residues with the same number,",
-        "the output can be less useful.[PAR]",
+        "the output can be less useful.",
+        "",
         "With [TT]-om[tt], a mask is printed for the first selection",
         "as a function of time. Each line in the output corresponds to",
         "one frame, and contains either 0/1 for each atom/residue/molecule",
         "possibly selected. 1 stands for the atom/residue/molecule being",
-        "selected for the current frame, 0 for not selected.[PAR]",
+        "selected for the current frame, 0 for not selected.",
+        "",
         "With [TT]-of[tt], the occupancy fraction of each position (i.e.,",
         "the fraction of frames where the position is selected) is",
-        "printed.[PAR]",
+        "printed.",
+        "",
         "With [TT]-ofpdb[tt], a PDB file is written out where the occupancy",
         "column is filled with the occupancy fraction of each atom in the",
         "selection. The coordinates in the PDB file will be those from the",
@@ -400,13 +408,16 @@ Select::initOptions(IOptionsContainer *options, TrajectoryAnalysisSettings *sett
         "appear in the output PDB file: with [TT]all[tt] all atoms are",
         "present, with [TT]maxsel[tt] all atoms possibly selected by the",
         "selection are present, and with [TT]selected[tt] only atoms that are",
-        "selected at least in one frame are present.[PAR]",
+        "selected at least in one frame are present.",
+        "",
         "With [TT]-olt[tt], a histogram is produced that shows the number of",
         "selected positions as a function of the time the position was",
         "continuously selected. [TT]-cumlt[tt] can be used to control whether",
         "subintervals of longer intervals are included in the histogram.[PAR]",
         "[TT]-om[tt], [TT]-of[tt], and [TT]-olt[tt] only make sense with",
-        "dynamic selections."
+        "dynamic selections.",
+        "",
+        "To plot coordinates for selections, use [gmx-trajectory]."
     };
 
     settings->setHelpText(desc);
@@ -436,9 +447,9 @@ Select::initOptions(IOptionsContainer *options, TrajectoryAnalysisSettings *sett
                            .store(&fnLifetime_).defaultBasename("lifetime")
                            .description("Lifetime histogram"));
 
-    selOpt_ = options->addOption(SelectionOption("select").storeVector(&sel_)
-                                     .required().multiValue()
-                                     .description("Selections to analyze"));
+    options->addOption(SelectionOption("select").storeVector(&sel_)
+                           .required().multiValue()
+                           .description("Selections to analyze"));
 
     options->addOption(BooleanOption("norm").store(&bTotNorm_)
                            .description("Normalize by total number of positions with -os"));
@@ -672,10 +683,14 @@ Select::writeOutput()
         t_pdbinfo         *pdbinfo;
         snew(pdbinfo, atoms.nr);
         scoped_guard_sfree pdbinfoGuard(pdbinfo);
-        if (atoms.pdbinfo != NULL)
+        if (atoms.havePdbInfo)
         {
             std::memcpy(pdbinfo, atoms.pdbinfo, atoms.nr*sizeof(*pdbinfo));
         }
+        else
+        {
+            atoms.havePdbInfo = TRUE;
+        }
         atoms.pdbinfo = pdbinfo;
         for (int i = 0; i < atoms.nr; ++i)
         {
diff --git a/src/gromacs/trajectoryanalysis/modules/trajectory.cpp b/src/gromacs/trajectoryanalysis/modules/trajectory.cpp
new file mode 100644 (file)
index 0000000..b83d188
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Implements gmx::analysismodules::Trajectory.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_trajectoryanalysis
+ */
+#include "gmxpre.h"
+
+#include "trajectory.h"
+
+#include <algorithm>
+
+#include "gromacs/analysisdata/analysisdata.h"
+#include "gromacs/analysisdata/modules/plot.h"
+#include "gromacs/fileio/trxio.h"
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/filenameoption.h"
+#include "gromacs/options/ioptionscontainer.h"
+#include "gromacs/selection/selection.h"
+#include "gromacs/selection/selectionoption.h"
+#include "gromacs/trajectory/trajectoryframe.h"
+#include "gromacs/trajectoryanalysis/analysissettings.h"
+
+namespace gmx
+{
+
+namespace analysismodules
+{
+
+namespace
+{
+
+/********************************************************************
+ * Trajectory
+ */
+
+class Trajectory : public TrajectoryAnalysisModule
+{
+    public:
+        Trajectory();
+
+        virtual void initOptions(IOptionsContainer          *options,
+                                 TrajectoryAnalysisSettings *settings);
+        virtual void optionsFinished(TrajectoryAnalysisSettings *settings);
+        virtual void initAnalysis(const TrajectoryAnalysisSettings &settings,
+                                  const TopologyInformation        &top);
+
+        virtual void analyzeFrame(int frnr, const t_trxframe &fr, t_pbc *pbc,
+                                  TrajectoryAnalysisModuleData *pdata);
+
+        virtual void finishAnalysis(int nframes);
+        virtual void writeOutput();
+
+    private:
+        SelectionList                       sel_;
+
+        std::string                         fnX_;
+        std::string                         fnV_;
+        std::string                         fnF_;
+        bool                                dimMask_[4];
+        bool                                maskSet_[4];
+
+        AnalysisData                        xdata_;
+        AnalysisData                        vdata_;
+        AnalysisData                        fdata_;
+};
+
+Trajectory::Trajectory()
+{
+    std::fill(std::begin(dimMask_), std::end(dimMask_), true);
+    dimMask_[DIM] = false;
+    std::fill(std::begin(maskSet_), std::end(maskSet_), false);
+    registerAnalysisDataset(&xdata_, "x");
+    registerAnalysisDataset(&vdata_, "v");
+    registerAnalysisDataset(&fdata_, "f");
+}
+
+
+void
+Trajectory::initOptions(IOptionsContainer *options, TrajectoryAnalysisSettings *settings)
+{
+    static const char *const desc[] = {
+        "[THISMODULE] plots coordinates, velocities, and/or forces for",
+        "provided selections. By default, the X, Y, and Z components for",
+        "the requested vectors are plotted, but specifying one or more of",
+        "[TT]-len[tt], [TT]-x[tt], [TT]-y[tt], and [TT]-z[tt] overrides this.",
+        "",
+        "For dynamic selections, currently the values are written out for",
+        "all positions that the selection could select."
+    };
+
+    settings->setHelpText(desc);
+
+    options->addOption(FileNameOption("ox").filetype(eftPlot).outputFile()
+                           .store(&fnX_).defaultBasename("coord")
+                           .description("Coordinates for each position as a function of time"));
+    options->addOption(FileNameOption("ov").filetype(eftPlot).outputFile()
+                           .store(&fnV_).defaultBasename("veloc")
+                           .description("Velocities for each position as a function of time"));
+    options->addOption(FileNameOption("of").filetype(eftPlot).outputFile()
+                           .store(&fnF_).defaultBasename("force")
+                           .description("Forces for each position as a function of time"));
+
+    options->addOption(SelectionOption("select").storeVector(&sel_)
+                           .required().dynamicMask().multiValue()
+                           .description("Selections to analyze"));
+
+    options->addOption(BooleanOption("x").store(&dimMask_[XX])
+                           .storeIsSet(&maskSet_[XX])
+                           .description("Plot X component"));
+    options->addOption(BooleanOption("y").store(&dimMask_[YY])
+                           .storeIsSet(&maskSet_[YY])
+                           .description("Plot Y component"));
+    options->addOption(BooleanOption("z").store(&dimMask_[ZZ])
+                           .storeIsSet(&maskSet_[ZZ])
+                           .description("Plot Z component"));
+    options->addOption(BooleanOption("len").store(&dimMask_[DIM])
+                           .storeIsSet(&maskSet_[DIM])
+                           .description("Plot vector length"));
+}
+
+
+void
+Trajectory::optionsFinished(TrajectoryAnalysisSettings *settings)
+{
+    int frameFlags = TRX_NEED_X;
+    if (!fnV_.empty())
+    {
+        frameFlags |= TRX_READ_V;
+    }
+    if (!fnF_.empty())
+    {
+        frameFlags |= TRX_READ_F;
+    }
+    settings->setFrameFlags(frameFlags);
+    if (std::count(std::begin(maskSet_), std::end(maskSet_), true) > 0)
+    {
+        for (int i = 0; i <= DIM; ++i)
+        {
+            if (!maskSet_[i])
+            {
+                dimMask_[i] = false;
+            }
+        }
+    }
+}
+
+
+void
+Trajectory::initAnalysis(const TrajectoryAnalysisSettings &settings,
+                         const TopologyInformation         & /*top*/)
+{
+    if (!fnX_.empty())
+    {
+        xdata_.setDataSetCount(sel_.size());
+        for (size_t g = 0; g < sel_.size(); ++g)
+        {
+            xdata_.setColumnCount(g, 3*sel_[g].posCount());
+        }
+        AnalysisDataVectorPlotModulePointer plot(
+                new AnalysisDataVectorPlotModule(settings.plotSettings()));
+        plot->setWriteMask(dimMask_);
+        plot->setFileName(fnX_);
+        plot->setTitle("Coordinates");
+        plot->setXAxisIsTime();
+        plot->setYLabel("Value [nm]");
+        xdata_.addModule(plot);
+    }
+    if (!fnV_.empty())
+    {
+        vdata_.setDataSetCount(sel_.size());
+        for (size_t g = 0; g < sel_.size(); ++g)
+        {
+            sel_[g].setEvaluateVelocities(true);
+            vdata_.setColumnCount(g, 3*sel_[g].posCount());
+        }
+        AnalysisDataVectorPlotModulePointer plot(
+                new AnalysisDataVectorPlotModule(settings.plotSettings()));
+        plot->setWriteMask(dimMask_);
+        plot->setFileName(fnV_);
+        plot->setTitle("Velocities");
+        plot->setXAxisIsTime();
+        plot->setYLabel("Value [nm/ps]");
+        vdata_.addModule(plot);
+    }
+    if (!fnF_.empty())
+    {
+        fdata_.setDataSetCount(sel_.size());
+        for (size_t g = 0; g < sel_.size(); ++g)
+        {
+            sel_[g].setEvaluateForces(true);
+            fdata_.setColumnCount(g, 3*sel_[g].posCount());
+        }
+        AnalysisDataVectorPlotModulePointer plot(
+                new AnalysisDataVectorPlotModule(settings.plotSettings()));
+        plot->setWriteMask(dimMask_);
+        plot->setFileName(fnF_);
+        plot->setTitle("Forces");
+        plot->setXAxisIsTime();
+        plot->setYLabel("Value [kJ mol\\S-1\\N nm\\S-1\\N]");
+        fdata_.addModule(plot);
+    }
+}
+
+
+void
+Trajectory::analyzeFrame(int frnr, const t_trxframe &fr, t_pbc * /* pbc */,
+                         TrajectoryAnalysisModuleData *pdata)
+{
+    const SelectionList &sel = pdata->parallelSelections(sel_);
+
+    // There is some duplication here, but cppcheck cannot handle function
+    // types that return rvec references, and MSVC also apparently segfaults
+    // when using std::function with a member function here...
+    {
+        AnalysisDataHandle dh = pdata->dataHandle(xdata_);
+        if (dh.isValid())
+        {
+            dh.startFrame(frnr, fr.time);
+            for (size_t g = 0; g < sel.size(); ++g)
+            {
+                dh.selectDataSet(g);
+                for (int i = 0; i < sel[g].posCount(); ++i)
+                {
+                    const SelectionPosition &pos = sel[g].position(i);
+                    dh.setPoints(i*3, 3, pos.x(), pos.selected());
+                }
+            }
+            dh.finishFrame();
+        }
+    }
+    if (fr.bV)
+    {
+        AnalysisDataHandle dh = pdata->dataHandle(xdata_);
+        if (dh.isValid())
+        {
+            dh.startFrame(frnr, fr.time);
+            for (size_t g = 0; g < sel.size(); ++g)
+            {
+                dh.selectDataSet(g);
+                for (int i = 0; i < sel[g].posCount(); ++i)
+                {
+                    const SelectionPosition &pos = sel[g].position(i);
+                    dh.setPoints(i*3, 3, pos.v(), pos.selected());
+                }
+            }
+            dh.finishFrame();
+        }
+    }
+    if (fr.bF)
+    {
+        AnalysisDataHandle dh = pdata->dataHandle(xdata_);
+        if (dh.isValid())
+        {
+            dh.startFrame(frnr, fr.time);
+            for (size_t g = 0; g < sel.size(); ++g)
+            {
+                dh.selectDataSet(g);
+                for (int i = 0; i < sel[g].posCount(); ++i)
+                {
+                    const SelectionPosition &pos = sel[g].position(i);
+                    dh.setPoints(i*3, 3, pos.f(), pos.selected());
+                }
+            }
+            dh.finishFrame();
+        }
+    }
+}
+
+
+void
+Trajectory::finishAnalysis(int /*nframes*/)
+{
+}
+
+
+void
+Trajectory::writeOutput()
+{
+}
+
+}       // namespace
+
+const char TrajectoryInfo::name[]             = "trajectory";
+const char TrajectoryInfo::shortDescription[] =
+    "Print coordinates, velocities, and/or forces for selections";
+
+TrajectoryAnalysisModulePointer TrajectoryInfo::create()
+{
+    return TrajectoryAnalysisModulePointer(new Trajectory);
+}
+
+} // namespace analysismodules
+
+} // namespace gmx
diff --git a/src/gromacs/trajectoryanalysis/modules/trajectory.h b/src/gromacs/trajectoryanalysis/modules/trajectory.h
new file mode 100644 (file)
index 0000000..1f510af
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Declares trajectory analysis module for basic trajectory information.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_trajectoryanalysis
+ */
+#ifndef GMX_TRAJECTORYANALYSIS_MODULES_TRAJECTORY_H
+#define GMX_TRAJECTORYANALYSIS_MODULES_TRAJECTORY_H
+
+#include "gromacs/trajectoryanalysis/analysismodule.h"
+
+namespace gmx
+{
+
+namespace analysismodules
+{
+
+class TrajectoryInfo
+{
+    public:
+        static const char name[];
+        static const char shortDescription[];
+        static TrajectoryAnalysisModulePointer create();
+};
+
+} // namespace analysismodules
+
+} // namespace gmx
+
+#endif
index 2ed120638e028cfa4cb8bfbe88b0ac5a559dc0c9..e146c5e2d6d2f0292c88e8ad194b771dad783b92 100644 (file)
@@ -90,10 +90,10 @@ class TrajectoryAnalysisRunnerCommon::Impl : public ITopologyProvider
         void finishTrajectory();
 
         // From ITopologyProvider
-        virtual t_topology *getTopology(bool required)
+        virtual gmx_mtop_t *getTopology(bool required)
         {
             initTopology(required);
-            return topInfo_.topology();
+            return topInfo_.mtop_;
         }
         virtual int getAtomCount()
         {
@@ -180,9 +180,21 @@ TrajectoryAnalysisRunnerCommon::Impl::initTopology(bool required)
     // Load the topology if requested.
     if (!topfile_.empty())
     {
-        snew(topInfo_.top_, 1);
-        topInfo_.bTop_ = read_tps_conf(topfile_.c_str(), topInfo_.top_, &topInfo_.ePBC_,
-                                       &topInfo_.xtop_, NULL, topInfo_.boxtop_, TRUE);
+        snew(topInfo_.mtop_, 1);
+        readConfAndTopology(topfile_.c_str(), &topInfo_.bTop_, topInfo_.mtop_,
+                            &topInfo_.ePBC_, &topInfo_.xtop_, NULL,
+                            topInfo_.boxtop_);
+        // TODO: Only load this here if the tool actually needs it; selections
+        // take care of themselves.
+        for (int i = 0; i < topInfo_.mtop_->nmoltype; ++i)
+        {
+            gmx_moltype_t &moltype = topInfo_.mtop_->moltype[i];
+            if (!moltype.atoms.haveMass)
+            {
+                // Try to read masses from database, be silent about missing masses
+                atomsSetMassesBasedOnNames(&moltype.atoms, FALSE);
+            }
+        }
         if (hasTrajectory()
             && !settings_.hasFlag(TrajectoryAnalysisSettings::efUseTopX))
         {
index b59d79fd980c1f8395c7fc1de09c19856b64219b..965330236a953ed53e7f228ee2552bf9693af9e5 100644 (file)
@@ -43,6 +43,7 @@ gmx_add_unit_test(TrajectoryAnalysisUnitTests trajectoryanalysis-test
                   sasa.cpp
                   select.cpp
                   surfacearea.cpp
+                  trajectory.cpp
                   $<TARGET_OBJECTS:analysisdata-test-shared>)
 
 add_executable(test_selection ${UNITTEST_TARGET_OPTIONS} test_selection.cpp)
index 06d7089fed4e5924b6c9ea9f9ae0cb4106fcb989..2eecb9af435ca89caa0b0955ef1795a82cb21a4f 100644 (file)
           </DataValue>
           <DataValue>
             <Real Name="Value">0</Real>
+            <Bool Name="Present">false</Bool>
           </DataValue>
           <DataValue>
             <Real Name="Value">1</Real>
+            <Bool Name="Present">false</Bool>
           </DataValue>
           <DataValue>
             <Real Name="Value">0</Real>
+            <Bool Name="Present">false</Bool>
           </DataValue>
           <DataValue>
             <Real Name="Value">0</Real>
+            <Bool Name="Present">false</Bool>
           </DataValue>
           <DataValue>
             <Real Name="Value">1</Real>
+            <Bool Name="Present">false</Bool>
           </DataValue>
           <DataValue>
             <Real Name="Value">0</Real>
+            <Bool Name="Present">false</Bool>
           </DataValue>
         </DataValues>
       </DataFrame>
diff --git a/src/gromacs/trajectoryanalysis/tests/refdata/TrajectoryModuleTest_BasicTest.xml b/src/gromacs/trajectoryanalysis/tests/refdata/TrajectoryModuleTest_BasicTest.xml
new file mode 100644 (file)
index 0000000..2d8c33b
--- /dev/null
@@ -0,0 +1,142 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <String Name="CommandLine">trajectory -select 'resnr 1' 'resnr 3'</String>
+  <OutputData Name="Data">
+    <AnalysisData Name="x">
+      <DataFrame Name="Frame0">
+        <Real Name="X">0</Real>
+        <DataValues>
+          <Int Name="Count">9</Int>
+          <Int Name="DataSet">0</Int>
+          <DataValue>
+            <Real Name="Value">4</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">4</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">2</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">4</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">3</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0</Real>
+          </DataValue>
+        </DataValues>
+        <DataValues>
+          <Int Name="Count">9</Int>
+          <Int Name="DataSet">1</Int>
+          <DataValue>
+            <Real Name="Value">1</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">4</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">2</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">2</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">2</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame1">
+        <Real Name="X">0</Real>
+        <DataValues>
+          <Int Name="Count">9</Int>
+          <Int Name="DataSet">0</Int>
+          <DataValue>
+            <Real Name="Value">4</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">2</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">4</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">3</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">4</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">4</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0</Real>
+          </DataValue>
+        </DataValues>
+        <DataValues>
+          <Int Name="Count">9</Int>
+          <Int Name="DataSet">1</Int>
+          <DataValue>
+            <Real Name="Value">1</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">2</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">2</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">3</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">2</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">4</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+    </AnalysisData>
+  </OutputData>
+  <OutputFiles Name="Files">
+    <File Name="-ox"></File>
+  </OutputFiles>
+</ReferenceData>
diff --git a/src/gromacs/trajectoryanalysis/tests/refdata/TrajectoryModuleTest_HandlesNoForces.xml b/src/gromacs/trajectoryanalysis/tests/refdata/TrajectoryModuleTest_HandlesNoForces.xml
new file mode 100644 (file)
index 0000000..13876a0
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <String Name="CommandLine">trajectory -select 'resnr 1' 'resnr 3'</String>
+  <OutputData Name="Data">
+    <AnalysisData Name="f"></AnalysisData>
+  </OutputData>
+  <OutputFiles Name="Files">
+    <File Name="-of"></File>
+  </OutputFiles>
+</ReferenceData>
diff --git a/src/gromacs/trajectoryanalysis/tests/refdata/TrajectoryModuleTest_HandlesNoVelocities.xml b/src/gromacs/trajectoryanalysis/tests/refdata/TrajectoryModuleTest_HandlesNoVelocities.xml
new file mode 100644 (file)
index 0000000..dc51121
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <String Name="CommandLine">trajectory -select 'resnr 1' 'resnr 3'</String>
+  <OutputData Name="Data">
+    <AnalysisData Name="v"></AnalysisData>
+  </OutputData>
+  <OutputFiles Name="Files">
+    <File Name="-ov"></File>
+  </OutputFiles>
+</ReferenceData>
diff --git a/src/gromacs/trajectoryanalysis/tests/refdata/TrajectoryModuleTest_PlotsXOnly.xml b/src/gromacs/trajectoryanalysis/tests/refdata/TrajectoryModuleTest_PlotsXOnly.xml
new file mode 100644 (file)
index 0000000..9715cae
--- /dev/null
@@ -0,0 +1,142 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <String Name="CommandLine">trajectory -select 'resnr 1' 'resnr 3' -x</String>
+  <OutputData Name="Data">
+    <AnalysisData Name="x">
+      <DataFrame Name="Frame0">
+        <Real Name="X">0</Real>
+        <DataValues>
+          <Int Name="Count">9</Int>
+          <Int Name="DataSet">0</Int>
+          <DataValue>
+            <Real Name="Value">4</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">4</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">2</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">4</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">3</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0</Real>
+          </DataValue>
+        </DataValues>
+        <DataValues>
+          <Int Name="Count">9</Int>
+          <Int Name="DataSet">1</Int>
+          <DataValue>
+            <Real Name="Value">1</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">4</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">2</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">2</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">2</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame1">
+        <Real Name="X">0</Real>
+        <DataValues>
+          <Int Name="Count">9</Int>
+          <Int Name="DataSet">0</Int>
+          <DataValue>
+            <Real Name="Value">4</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">2</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">4</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">3</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">4</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">4</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0</Real>
+          </DataValue>
+        </DataValues>
+        <DataValues>
+          <Int Name="Count">9</Int>
+          <Int Name="DataSet">1</Int>
+          <DataValue>
+            <Real Name="Value">1</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">2</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">2</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">3</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">2</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">4</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+    </AnalysisData>
+  </OutputData>
+  <OutputFiles Name="Files">
+    <File Name="-ox"></File>
+  </OutputFiles>
+</ReferenceData>
index 30dc1a344eedc16ce8d74c6b7caed2c846827a52..f7607f6264913e1a20bf65873fb26fd2de0a8d9a 100644 (file)
@@ -88,7 +88,7 @@ class SurfaceAreaTest : public ::testing::Test
             {
                 index_.push_back(x_.size());
             }
-            x_.push_back(gmx::RVec(x, y, z));
+            x_.emplace_back(x, y, z);
             radius_.push_back(radius);
         }
 
diff --git a/src/gromacs/trajectoryanalysis/tests/trajectory.cpp b/src/gromacs/trajectoryanalysis/tests/trajectory.cpp
new file mode 100644 (file)
index 0000000..2124ebe
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Tests for functionality of the "trajectory" trajectory analysis module.
+ *
+ * Line coverage for the module code is good, but due to missing input data
+ * with velocities or forces, the output of these quantities is not really
+ * tested.  But the values are only computed in the selection engine, and
+ * at least the low-level computation is tested there.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_trajectoryanalysis
+ */
+#include "gmxpre.h"
+
+#include "gromacs/trajectoryanalysis/modules/trajectory.h"
+
+#include <gtest/gtest.h>
+
+#include "testutils/cmdlinetest.h"
+#include "testutils/textblockmatchers.h"
+
+#include "moduletest.h"
+
+namespace
+{
+
+using gmx::test::CommandLine;
+using gmx::test::NoTextMatch;
+
+/********************************************************************
+ * Tests for gmx::analysismodules::Trajectory.
+ */
+
+//! Test fixture for the select analysis module.
+typedef gmx::test::TrajectoryAnalysisModuleTestFixture<gmx::analysismodules::TrajectoryInfo>
+    TrajectoryModuleTest;
+
+TEST_F(TrajectoryModuleTest, BasicTest)
+{
+    const char *const cmdline[] = {
+        "trajectory",
+        "-select", "resnr 1", "resnr 3"
+    };
+    setTopology("simple.gro");
+    setTrajectory("simple.gro");
+    setOutputFile("-ox", "coord.xvg", NoTextMatch());
+    includeDataset("x");
+    runTest(CommandLine(cmdline));
+}
+
+TEST_F(TrajectoryModuleTest, PlotsXOnly)
+{
+    const char *const cmdline[] = {
+        "trajectory",
+        "-select", "resnr 1", "resnr 3",
+        "-x"
+    };
+    setTopology("simple.gro");
+    setTrajectory("simple.gro");
+    setOutputFile("-ox", "coord.xvg", NoTextMatch());
+    includeDataset("x");
+    runTest(CommandLine(cmdline));
+}
+
+TEST_F(TrajectoryModuleTest, HandlesNoVelocities)
+{
+    const char *const cmdline[] = {
+        "trajectory",
+        "-select", "resnr 1", "resnr 3",
+    };
+    setTopology("simple.gro");
+    setTrajectory("simple.gro");
+    setOutputFile("-ov", "vel.xvg", NoTextMatch());
+    includeDataset("v");
+    runTest(CommandLine(cmdline));
+}
+
+TEST_F(TrajectoryModuleTest, HandlesNoForces)
+{
+    const char *const cmdline[] = {
+        "trajectory",
+        "-select", "resnr 1", "resnr 3",
+    };
+    setTopology("simple.gro");
+    setTrajectory("simple.gro");
+    setOutputFile("-of", "force.xvg", NoTextMatch());
+    includeDataset("f");
+    runTest(CommandLine(cmdline));
+}
+
+} // namespace
index 0602323c3231fa225c02dae9c338543a3491722b..609b906cbeaa7b23473ff8a0881e9f39e659338c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  * managing directories and files.
  * The fate of this header depends on what is decided in Redmine issue #950.
  *
+ * <H3>Logging</H3>
+ *
+ * The headers logger.h and loggerbuilder.h provide interfaces and classes for
+ * writing log files (or logging to other targets).  See \ref page_logging for
+ * an overview.
+ *
  * \endif
  *
  * <H3>Implementation helpers</H3>
  *
  * \if libapi
  *
+ * The header strconvert.h declares string parsing routines.
+ *
  * The header gmxmpi.h abstracts away the mechanism of including either MPI or
  * thread-MPI headers depending on compilation options.
  * Similarly, gmxomp.h removes the need to use conditional compilation for code
index df6769428f2600f46a414189f7727e0608ca35f9..56d1b2e6743ee763978cebe0068de20abbd4018b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -239,7 +239,7 @@ class AlignedAllocator
          */
         template<class T2>
         bool
-        operator==(const AlignedAllocator<T2> &gmx_unused rhs) const { return std::is_same<T, T2>::value; }
+        operator==(const AlignedAllocator<T2> &gmx_unused rhs) const { return std::is_same<T, T2>::value; GMX_UNUSED_VALUE(rhs); }
 
         /*! \brief Return true if two allocators are different
          *
index ccf6e5e9d04202aed0ac46cf265c7b1dec1b6b2a..0538fb8f57fc8d222adaf2fd2bdc893bc9e4f1e9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -45,6 +45,7 @@
 
 #include <cstddef>
 
+#include <array>
 #include <iterator>
 #include <stdexcept>
 #include <utility>
@@ -67,8 +68,8 @@ namespace gmx
  */
 struct EmptyArrayRef {};
 
-/*! \brief
- * STL-like container for an interface to a C array (or part of a std::vector).
+/*! \brief STL-like container for an interface to a C array of T (or part
+ * of a std::vector<T> or std::array<T>).
  *
  * \tparam T  Value type of elements.
  *
@@ -76,14 +77,15 @@ struct EmptyArrayRef {};
  * following main differences:
  *  - This class does not have its own storage.  Instead, it references an
  *    existing array of values (either a C-style array or part of an existing
- *    std::vector<T>).
+ *    std::vector<T> or std::array<T>).
  *  - It is only possible to modify the values themselves through ArrayRef;
  *    it is not possible to add or remove values.
  *  - Copying objects of this type is cheap, and the copies behave identically
  *    to the original object: the copy references the same set of values.
  *
- * This class is useful for writing wrappers that expose a different view of
- * the internal data stored as a single vector/array.
+ * This class is useful for writing wrappers that expose a view of the
+ * internal data stored as a single vector/array, which can be a whole
+ * or part of the underlying storage.
  *
  * Methods in this class do not throw, except where indicated.
  *
@@ -199,7 +201,7 @@ class ArrayRef
             GMX_ASSERT(end >= begin, "Invalid range");
         }
         /*! \brief
-         * Constructs a reference to a whole vector.
+         * Constructs a reference to a whole std::vector<T>.
          *
          * \param[in] v  Vector to reference.
          *
@@ -207,13 +209,30 @@ class ArrayRef
          * lifetime of this object.
          *
          * This constructor is not explicit to allow directly passing
-         * std::vector to a method that takes ArrayRef.
+         * std::vector<T> to a method that takes ArrayRef.
          */
         ArrayRef(std::vector<T> &v)
             : begin_((!v.empty()) ? &v[0] : NULL),
               end_((!v.empty()) ? &v[0] + v.size() : NULL)
         {
         }
+        /*! \brief
+         * Constructs a reference to a whole std::array<T>.
+         *
+         * \param[in] a  Array to reference.
+         *
+         * Passed array must remain valid for the lifetime of this
+         * object.
+         *
+         * This constructor is not explicit to allow directly passing
+         * std::array<T> to a method that takes ArrayRef.
+         */
+        template <size_t count>
+        ArrayRef(std::array<T, count> &a)
+            : begin_((!a.empty()) ? &a[0] : NULL),
+              end_((!a.empty()) ? &a[0] + a.size() : NULL)
+        {
+        }
         //! \cond
         // Doxygen 1.8.5 doesn't parse the declaration correctly...
         /*! \brief
@@ -231,11 +250,6 @@ class ArrayRef
          *
          * This constructor is not explicit to allow directly passing
          * a C array to a function that takes an ArrayRef parameter.
-         *
-         * xlc on BG/Q compiles wrong code if the C array is a struct
-         * field, unless value_type is char or unsigned char. There's
-         * no good way to assert on this before C++11 (which that
-         * compiler will never support).
          */
         template <size_t count>
         ArrayRef(value_type (&array)[count])
@@ -323,9 +337,8 @@ class ArrayRef
 
 
 
-/*! \brief
- * STL-like container for non-mutable interface to a C array (or part of a
- * std::vector).
+/*! \brief STL-like container for non-mutable interface to a C array of T
+ * (or part of a std::vector<T> or std::array<T>).
  *
  * \tparam T  Value type of elements.
  *
@@ -333,14 +346,15 @@ class ArrayRef
  * following main differences:
  *  - This class does not have its own storage.  Instead, it references an
  *    existing array of values (either a C-style array or part of an existing
- *    std::vector<T>).
+ *    std::vector<T> or std::array<T>).
  *  - Only const methods are provided to access the stored values.
  *    It is not possible to alter the referenced array.
  *  - Copying objects of this type is cheap, and the copies behave identically
  *    to the original object: the copy references the same set of values.
  *
- * This class is useful for writing wrappers that expose a different view of
- * the internal data stored as a single vector/array.
+ * This class is useful for writing wrappers that expose a view of the
+ * internal data stored as a single vector/array, which can be a whole
+ * or part of the underlying storage.
  *
  * Methods in this class do not throw, except where indicated.
  *
@@ -411,6 +425,10 @@ class ConstArrayRef
          * template type.  It is not explicit to enable that usage.
          */
         ConstArrayRef(const EmptyArrayRef &) : begin_(NULL), end_(NULL) {}
+        /*! \brief
+         * Constructs a const reference from a non-const reference.
+         */
+        ConstArrayRef(const ArrayRef<T> &other) : begin_(other.begin()), end_(other.end()) {}
         /*! \brief
          * Constructs a reference to a particular range.
          *
@@ -428,7 +446,7 @@ class ConstArrayRef
             GMX_ASSERT(end >= begin, "Invalid range");
         }
         /*! \brief
-         * Constructs a reference to a whole vector.
+         * Constructs a reference to a whole std::vector<T>.
          *
          * \param[in] v  Vector to reference.
          *
@@ -436,13 +454,30 @@ class ConstArrayRef
          * lifetime of this object.
          *
          * This constructor is not explicit to allow directly passing
-         * std::vector to a method that takes ConstArrayRef.
+         * std::vector<T> to a method that takes ConstArrayRef.
          */
         ConstArrayRef(const std::vector<T> &v)
             : begin_((!v.empty()) ? &v[0] : NULL),
               end_((!v.empty()) ? &v[0] + v.size() : NULL)
         {
         }
+        /*! \brief
+         * Constructs a reference to a whole std::array<T>.
+         *
+         * \param[in] a  Array to reference.
+         *
+         * Passed array must remain valid for the lifetime of this
+         * object.
+         *
+         * This constructor is not explicit to allow directly passing
+         * std::array<T> to a method that takes ConstArrayRef.
+         */
+        template <size_t count>
+        ConstArrayRef(const std::array<T, count> &a)
+            : begin_((!a.empty()) ? &a[0] : NULL),
+              end_((!a.empty()) ? &a[0] + a.size() : NULL)
+        {
+        }
         //! \cond
         // Doxygen 1.8.5 doesn't parse the declaration correctly...
         /*! \brief
@@ -460,11 +495,6 @@ class ConstArrayRef
          *
          * This constructor is not explicit to allow directly passing
          * a C array to a function that takes a ConstArrayRef parameter.
-         *
-         * xlc on BG/Q compiles wrong code if the C array is a struct
-         * field, unless value_type is char or unsigned char. There's
-         * no good way to assert on this before C++11 (which that
-         * compiler will never support).
          */
         template <size_t count>
         ConstArrayRef(const value_type (&array)[count])
index 47a820a04588e8650ed5f7a9ece8ee3dc757d02f..509b8747a1af9f69299b78566395ed683cff91a9 100644 (file)
@@ -255,18 +255,10 @@ typedef uint64_t gmx_uint64_t;
    \endcode
  */
 
-#if (defined(__GNUC__) && !defined(__clang__)) || defined(__ibmxl__) || defined(__xlC__) || defined(__PATHCC__)
-// Gcc-4.6.4 does not support alignas, but both gcc, pathscale and xlc
-// support the standard GNU alignment attributes. PGI also sets __GNUC__ now,
-// and mostly supports it. clang 3.2 does not support the GCC alignment attribute.
-#    define GMX_ALIGNED(type, alignment) __attribute__ ((aligned(alignment*sizeof(type)))) type
-#else
-// If nothing else works we rely on C++11. This will for instance work for MSVC2015 and later.
+// We rely on C++11. This will for instance work for MSVC2015 and later.
 // If you get an error here, find out what attribute to use to get your compiler to align
 // data properly and add it as a case.
-#    define GMX_ALIGNED(type, alignment) alignas(alignment*alignof(type)) type
-#endif
-
+#define GMX_ALIGNED(type, alignment) alignas(alignment*sizeof(type)) type
 
 /*! \brief
  * Macro to explicitly ignore an unused value.
index 6dceffc528b3832a1e67c714e8438d52caf5438d..3714313fe6cd5dea3dc9172ea09df8c7fc4d531c 100644 (file)
@@ -52,6 +52,7 @@
 namespace gmx
 {
 
+#ifdef DOXYGEN
 /*! \brief
  * Macro to declare a class non-copyable and non-assignable.
  *
@@ -59,9 +60,12 @@ namespace gmx
  *
  * \ingroup module_utility
  */
+#define GMX_DISALLOW_COPY_AND_ASSIGN(ClassName)
+#else
 #define GMX_DISALLOW_COPY_AND_ASSIGN(ClassName) \
     ClassName &operator=(const ClassName &) = delete;   \
     ClassName(const ClassName &)            = delete
+#endif
 /*! \brief
  * Macro to declare a class non-assignable.
  *
diff --git a/src/gromacs/utility/compare.cpp b/src/gromacs/utility/compare.cpp
new file mode 100644 (file)
index 0000000..95e9fce
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2004, The GROMACS development team.
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/* This file is completely threadsafe - keep it that way! */
+
+#include "gmxpre.h"
+
+#include "compare.h"
+
+#include <cmath>
+#include <cstdio>
+#include <cstring>
+
+#include "gromacs/utility/stringutil.h"
+
+void cmp_int(FILE *fp, const char *s, int index, int i1, int i2)
+{
+    if (i1 != i2)
+    {
+        if (index != -1)
+        {
+            fprintf(fp, "%s[%d] (%d - %d)\n", s, index, i1, i2);
+        }
+        else
+        {
+            fprintf(fp, "%s (%d - %d)\n", s, i1, i2);
+        }
+    }
+}
+
+void cmp_int64(FILE *fp, const char *s, gmx_int64_t i1, gmx_int64_t i2)
+{
+    if (i1 != i2)
+    {
+        fprintf(fp, "%s (", s);
+        fprintf(fp, "%" GMX_PRId64, i1);
+        fprintf(fp, " - ");
+        fprintf(fp, "%" GMX_PRId64, i2);
+        fprintf(fp, ")\n");
+    }
+}
+
+void cmp_us(FILE *fp, const char *s, int index, unsigned short i1, unsigned short i2)
+{
+    if (i1 != i2)
+    {
+        if (index != -1)
+        {
+            fprintf(fp, "%s[%d] (%hu - %hu)\n", s, index, i1, i2);
+        }
+        else
+        {
+            fprintf(fp, "%s (%hu - %hu)\n", s, i1, i2);
+        }
+    }
+}
+
+void cmp_uc(FILE *fp, const char *s, int index, unsigned char i1, unsigned char i2)
+{
+    if (i1 != i2)
+    {
+        if (index != -1)
+        {
+            fprintf(fp, "%s[%d] (%d - %d)\n", s, index, i1, i2);
+        }
+        else
+        {
+            fprintf(fp, "%s (%d - %d)\n", s, i1, i2);
+        }
+    }
+}
+
+gmx_bool cmp_bool(FILE *fp, const char *s, int index, gmx_bool b1, gmx_bool b2)
+{
+    if (b1)
+    {
+        b1 = 1;
+    }
+    else
+    {
+        b1 = 0;
+    }
+    if (b2)
+    {
+        b2 = 1;
+    }
+    else
+    {
+        b2 = 0;
+    }
+    if (b1 != b2)
+    {
+        if (index != -1)
+        {
+            fprintf(fp, "%s[%d] (%s - %s)\n", s, index,
+                    gmx::boolToString(b1), gmx::boolToString(b2));
+        }
+        else
+        {
+            fprintf(fp, "%s (%s - %s)\n", s,
+                    gmx::boolToString(b1), gmx::boolToString(b2));
+        }
+    }
+    return b1 && b2;
+}
+
+void cmp_str(FILE *fp, const char *s, int index, const char *s1, const char *s2)
+{
+    if (std::strcmp(s1, s2) != 0)
+    {
+        if (index != -1)
+        {
+            fprintf(fp, "%s[%d] (%s - %s)\n", s, index, s1, s2);
+        }
+        else
+        {
+            fprintf(fp, "%s (%s - %s)\n", s, s1, s2);
+        }
+    }
+}
+
+gmx_bool equal_real(real i1, real i2, real ftol, real abstol)
+{
+    return ( ( 2*fabs(i1 - i2) <= (fabs(i1) + fabs(i2))*ftol ) || fabs(i1-i2) <= abstol );
+}
+
+static gmx_bool equal_float(float i1, float i2, float ftol, float abstol)
+{
+    return ( ( 2*fabs(i1 - i2) <= (fabs(i1) + fabs(i2))*ftol ) || fabs(i1-i2) <= abstol );
+}
+
+static gmx_bool equal_double(double i1, double i2, real ftol, real abstol)
+{
+    return ( ( 2*fabs(i1 - i2) <= (fabs(i1) + fabs(i2))*ftol ) || fabs(i1-i2) <= abstol );
+}
+
+void
+cmp_real(FILE *fp, const char *s, int index, real i1, real i2, real ftol, real abstol)
+{
+    if (!equal_real(i1, i2, ftol, abstol))
+    {
+        if (index != -1)
+        {
+            fprintf(fp, "%s[%2d] (%e - %e)\n", s, index, i1, i2);
+        }
+        else
+        {
+            fprintf(fp, "%s (%e - %e)\n", s, i1, i2);
+        }
+    }
+}
+
+void
+cmp_float(FILE *fp, const char *s, int index, float i1, float i2, float ftol, float abstol)
+{
+    if (!equal_float(i1, i2, ftol, abstol))
+    {
+        if (index != -1)
+        {
+            fprintf(fp, "%s[%2d] (%e - %e)\n", s, index, i1, i2);
+        }
+        else
+        {
+            fprintf(fp, "%s (%e - %e)\n", s, i1, i2);
+        }
+    }
+}
+
+void
+cmp_double(FILE *fp, const char *s, int index, double i1, double i2, double ftol, double abstol)
+{
+    if (!equal_double(i1, i2, ftol, abstol))
+    {
+        if (index != -1)
+        {
+            fprintf(fp, "%s[%2d] (%16.9e - %16.9e)\n", s, index, i1, i2);
+        }
+        else
+        {
+            fprintf(fp, "%s (%16.9e - %16.9e)\n", s, i1, i2);
+        }
+    }
+}
diff --git a/src/gromacs/utility/compare.h b/src/gromacs/utility/compare.h
new file mode 100644 (file)
index 0000000..51e1f67
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2004, The GROMACS development team.
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Utilities for comparing data structures (for gmx check).
+ *
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+#ifndef GMX_UTILITY_COMPARE_H
+#define GMX_UTILITY_COMPARE_H
+
+#include <cstdio>
+
+#include "gromacs/utility/basedefinitions.h"
+#include "gromacs/utility/real.h"
+
+//! Compares two real values for equality.
+gmx_bool equal_real(real i1, real i2, real ftol, real abstol);
+
+//! Compares two integers and prints differences.
+void cmp_int(FILE *fp, const char *s, int index, int i1, int i2);
+
+//! Compares two 64-bit integers and prints differences.
+void cmp_int64(FILE *fp, const char *s, gmx_int64_t i1, gmx_int64_t i2);
+
+//! Compares two unsigned short values and prints differences.
+void cmp_us(FILE *fp, const char *s, int index, unsigned short i1, unsigned short i2);
+
+//! Compares two unsigned char values and prints differences.
+void cmp_uc(FILE *fp, const char *s, int index, unsigned char i1, unsigned char i2);
+
+//! Compares two boolean values and prints differences, and returns whether both are true.
+gmx_bool cmp_bool(FILE *fp, const char *s, int index, gmx_bool b1, gmx_bool b2);
+
+//! Compares two strings and prints differences.
+void cmp_str(FILE *fp, const char *s, int index, const char *s1, const char *s2);
+
+//! Compares two reals and prints differences.
+void cmp_real(FILE *fp, const char *s, int index, real i1, real i2, real ftol, real abstol);
+
+//! Compares two floats and prints differences.
+void cmp_float(FILE *fp, const char *s, int index, float i1, float i2, float ftol, float abstol);
+
+//! Compares two doubles and prints differences.
+void cmp_double(FILE *fp, const char *s, int index, double i1, double i2, double ftol, double abstol);
+
+#endif
index def9fe79dd0ee53b22bf741413844a8808db4fe5..61986b561be890b76068a1bbf147dbc3f14668a8 100644 (file)
@@ -736,6 +736,12 @@ std::string getCoolQuote()
         { "They don't have half hours in the north", "Carl Caleman" },
         { "Safety lights are for dudes", "Ghostbusters 2016" },
         { "It's 2040 now. Our President is a plant.",  "Ghostbusters 2016" },
+        { "It's just B I O L O G Y, can't you see?" "Joe Jackson" },
+        { "Input, output, electricity", "Joni Mitchell" },
+        { "Your daddy ain't your daddy but your daddy don't know", "Dalahan" },
+        { "Why is the Earth moving 'round the sun? Floating in the vacuum with no purpose, not a one", "Fleet Foxes" },
+        { "If you leave markets to act as governments, then sure as night follows day, the market will make people suffer and it will turn the world into a wilderness", "Ann Pettifor" },
+        { "If you look back to the fifties, what all economist call the golden age of economics, 1945-1970 was a period of economic stability, economic activity, pretty much full employment because we managed capital flows, we managed interest rates, we managed exchange rates. We coordinated at an international level to maintain balance in the global economy, we had a golden age. And now we're being told, you can't have another golden age, now we have to go through a period of fascism, this is necessary. Excuse me?", "Ann Pettifor" },
     };
 
     if (beCool())
index af7020e9395e129e74add506c511d3ba9a339108..598997ed33a020298abae4df8aba2853daa137a1 100644 (file)
@@ -227,7 +227,7 @@ DataFileFinder::enumerateFiles(const DataFileOptions &options) const
                         ".", options.filename_, false);
         for (i = files.begin(); i != files.end(); ++i)
         {
-            result.push_back(DataFileInfo(".", *i, false));
+            result.emplace_back(".", *i, false);
         }
     }
     if (impl_ != nullptr)
@@ -240,7 +240,7 @@ DataFileFinder::enumerateFiles(const DataFileOptions &options) const
                             j->c_str(), options.filename_, false);
             for (i = files.begin(); i != files.end(); ++i)
             {
-                result.push_back(DataFileInfo(*j, *i, false));
+                result.emplace_back(*j, *i, false);
             }
         }
     }
@@ -252,7 +252,7 @@ DataFileFinder::enumerateFiles(const DataFileOptions &options) const
                         defaultPath.c_str(), options.filename_, false);
         for (i = files.begin(); i != files.end(); ++i)
         {
-            result.push_back(DataFileInfo(defaultPath, *i, true));
+            result.emplace_back(defaultPath, *i, true);
         }
     }
     if (result.empty() && options.bThrow_)
index 879d66a3248e03a1a123e6e2233d7309dd07cb0c..d18c8bd1164d7a9f9c33a57707927ec3ae8dd5d4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -64,6 +64,7 @@ const char *const error_names[] =
     "System I/O error",
     "Error in user input",
     "Inconsistency in user input",
+    "Requested tolerance cannot be achieved",
     "Simulation instability detected",
 
     "Feature not implemented",
index 9d2b084d4c4527cf35ec24073dbd555507a1dfbd..b8158c63b3a1eab5ea3452bc7db015f6963277c7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -67,6 +67,8 @@ enum ErrorCode
     eeInvalidInput,
     //! Invalid user input (conflicting or unsupported settings).
     eeInconsistentInput,
+    //! Requested tolerance cannot be achieved.
+    eeTolerance,
     //! Simulation instability detected.
     eeInstability,
 
index e0d1325980da8cc7d1f22c6264d700097d4aa264..ed4a3fe1473adb77c9381739f1f0781fb6d0f70b 100644 (file)
@@ -245,6 +245,11 @@ int InconsistentInputError::errorCode() const
     return eeInconsistentInput;
 }
 
+int ToleranceError::errorCode() const
+{
+    return eeTolerance;
+}
+
 int SimulationInstabilityError::errorCode() const
 {
     return eeInstability;
@@ -260,6 +265,11 @@ int APIError::errorCode() const
     return eeAPIError;
 }
 
+int RangeError::errorCode() const
+{
+    return eeRange;
+}
+
 int NotImplementedError::errorCode() const
 {
     return eeNotImplemented;
index 13e4f8f734ad04f4af82197966374f052eded8b3..fd66bdb98870ca2fafa92a5fcd9ab49257cd6726 100644 (file)
@@ -462,6 +462,30 @@ class InconsistentInputError : public UserInputError
         virtual int errorCode() const;
 };
 
+/*! \brief
+ * Exception class when a specified tolerance cannot be achieved.
+ *
+ * \inpublicapi
+ */
+class ToleranceError : public GromacsException
+{
+    public:
+        /*! \brief
+         * Creates an exception object with the provided initializer/reason.
+         *
+         * \param[in] details  Initializer for the exception.
+         * \throws    std::bad_alloc if out of memory.
+         *
+         * It is possible to call this constructor either with an explicit
+         * ExceptionInitializer object (useful for more complex cases), or
+         * a simple string if only a reason string needs to be provided.
+         */
+        explicit ToleranceError(const ExceptionInitializer &details)
+            : GromacsException(details) {}
+
+        virtual int errorCode() const;
+};
+
 /*! \brief
  * Exception class for simulation instabilities.
  *
@@ -507,6 +531,21 @@ class APIError : public GromacsException
         virtual int errorCode() const;
 };
 
+/*! \brief
+ * Exception class for out-of-range values or indices
+ *
+ * \inpublicapi
+ */
+class RangeError : public GromacsException
+{
+    public:
+        //! \copydoc FileIOError::FileIOError()
+        explicit RangeError(const ExceptionInitializer &details)
+            : GromacsException(details) {}
+
+        virtual int errorCode() const;
+};
+
 /*! \brief
  * Exception class for use of an unimplemented feature.
  *
@@ -522,7 +561,6 @@ class NotImplementedError : public APIError
         virtual int errorCode() const;
 };
 
-
 /*! \brief
  * Macro for throwing an exception.
  *
index e093b3692a2fcd674a30610f257cfe4a80913aaa..eb2942a1f4e8bbfe0538d7f8a1edcc0a80d8e390 100644 (file)
@@ -34,7 +34,7 @@
  */
 /*! \libinternal \file
  * \brief
- * Wraps <mpi.h> usage in Gromacs.
+ * Wraps mpi.h usage in Gromacs.
  *
  * This header wraps the MPI header <mpi.h>, and should be included instead of
  * that one.  It abstracts away the case that depending on compilation
diff --git a/src/gromacs/utility/ikeyvaluetreeerror.cpp b/src/gromacs/utility/ikeyvaluetreeerror.cpp
new file mode 100644 (file)
index 0000000..4afe797
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+#include "gmxpre.h"
+
+#include "ikeyvaluetreeerror.h"
+
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/keyvaluetree.h"
+#include "gromacs/utility/stringutil.h"
+
+namespace gmx
+{
+
+namespace
+{
+
+class DefaultKeyValueTreeErrorHandler : public IKeyValueTreeErrorHandler
+{
+    public:
+        virtual bool onError(UserInputError *ex, const KeyValueTreePath &context)
+        {
+            std::string message
+                = formatString("While processing '%s':", context.toString().c_str());
+            ex->prependContext(message);
+            return false;
+        }
+};
+
+}   // namespace
+
+IKeyValueTreeErrorHandler::~IKeyValueTreeErrorHandler()
+{
+}
+
+//! \cond libapi
+IKeyValueTreeErrorHandler *defaultKeyValueTreeErrorHandler()
+{
+    static DefaultKeyValueTreeErrorHandler instance;
+    return &instance;
+}
+//! \endcond
+
+} // namespace gmx
diff --git a/src/gromacs/utility/ikeyvaluetreeerror.h b/src/gromacs/utility/ikeyvaluetreeerror.h
new file mode 100644 (file)
index 0000000..5917cb5
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares an error handling interface for key-value tree operations.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+#ifndef GMX_UTILITY_KEYVALUETREEERROR_H
+#define GMX_UTILITY_KEYVALUETREEERROR_H
+
+namespace gmx
+{
+
+class KeyValueTreePath;
+class UserInputError;
+
+class IKeyValueTreeErrorHandler
+{
+    public:
+        virtual bool onError(UserInputError *ex, const KeyValueTreePath &context) = 0;
+
+    protected:
+        ~IKeyValueTreeErrorHandler();
+};
+
+//! \cond libapi
+/*! \brief
+ * Returns a default IKeyValueTreeErrorHandler that throws on first exception.
+ *
+ * \ingroup module_utility
+ */
+IKeyValueTreeErrorHandler *defaultKeyValueTreeErrorHandler();
+//! \endcond
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/utility/iserializer.h b/src/gromacs/utility/iserializer.h
new file mode 100644 (file)
index 0000000..52b4f88
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares a generic serialization interface that supports both directions.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+#ifndef GMX_UTILITY_ISERIALIZER_H
+#define GMX_UTILITY_ISERIALIZER_H
+
+#include <string>
+
+namespace gmx
+{
+
+class ISerializer
+{
+    public:
+        virtual ~ISerializer() {}
+
+        virtual bool reading() const = 0;
+
+        virtual void doUChar(unsigned char *value) = 0;
+        virtual void doInt(int *value)             = 0;
+        virtual void doFloat(float *value)         = 0;
+        virtual void doDouble(double *value)       = 0;
+        virtual void doString(std::string *value)  = 0;
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/utility/keyvaluetree.cpp b/src/gromacs/utility/keyvaluetree.cpp
new file mode 100644 (file)
index 0000000..a71c1da
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+#include "gmxpre.h"
+
+#include "keyvaluetree.h"
+
+#include <string>
+#include <vector>
+
+#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/stringutil.h"
+
+namespace gmx
+{
+
+/********************************************************************
+ * KeyValueTreePath
+ */
+
+namespace
+{
+
+//! Helper function to split a KeyValueTreePath to its components
+std::vector<std::string> splitPathElements(const std::string &path)
+{
+    GMX_ASSERT(!path.empty() && path[0] == '/',
+               "Paths to KeyValueTree should start with '/'");
+    return splitDelimitedString(path.substr(1), '/');
+}
+
+}   // namespace
+
+KeyValueTreePath::KeyValueTreePath(const std::string &path)
+    : path_(splitPathElements(path))
+{
+}
+
+std::string KeyValueTreePath::toString() const
+{
+    return "/" + joinStrings(path_, "/");
+}
+
+} // namespace gmx
diff --git a/src/gromacs/utility/keyvaluetree.h b/src/gromacs/utility/keyvaluetree.h
new file mode 100644 (file)
index 0000000..f0ad626
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares a data structure for JSON-like structured key-value mapping.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+#ifndef GMX_UTILITY_KEYVALUETREE_H
+#define GMX_UTILITY_KEYVALUETREE_H
+
+#include <algorithm>
+#include <functional>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "gromacs/utility/variant.h"
+
+namespace gmx
+{
+
+class KeyValueTreeArray;
+class KeyValueTreeObject;
+
+class KeyValueTreePath
+{
+    public:
+        KeyValueTreePath() = default;
+        KeyValueTreePath(const std::string &path);
+
+        void append(const std::string &key) { path_.push_back(key); }
+        void pop_back() { return path_.pop_back(); }
+        std::string pop_last()
+        {
+            std::string result = std::move(path_.back());
+            path_.pop_back();
+            return result;
+        }
+
+        bool empty() const { return path_.empty(); }
+        size_t size() const { return path_.size(); }
+        const std::string &operator[](int i) const { return path_[i]; }
+        const std::vector<std::string> &elements() const { return path_; }
+
+        std::string toString() const;
+
+    private:
+        std::vector<std::string> path_;
+};
+
+class KeyValueTreeValue
+{
+    public:
+        bool isArray() const;
+        bool isObject() const;
+        template <typename T>
+        bool isType() const { return value_.isType<T>(); }
+        std::type_index type() const { return value_.type(); }
+
+        const KeyValueTreeArray  &asArray() const;
+        const KeyValueTreeObject &asObject() const;
+        template <typename T>
+        const T                  &cast() const { return value_.cast<T>(); }
+
+        const Variant            &asVariant() const { return value_; }
+
+    private:
+        explicit KeyValueTreeValue(Variant &&value) : value_(std::move(value)) {}
+
+        KeyValueTreeArray &asArray();
+        KeyValueTreeObject &asObject();
+
+        Variant             value_;
+
+        friend class KeyValueTreeBuilder;
+        friend class KeyValueTreeObjectBuilder;
+        friend class KeyValueTreeValueBuilder;
+};
+
+class KeyValueTreeArray
+{
+    public:
+        bool isObjectArray() const
+        {
+            return std::all_of(values_.begin(), values_.end(),
+                               std::mem_fn(&KeyValueTreeValue::isObject));
+        }
+
+        const std::vector<KeyValueTreeValue> &values() const { return values_; }
+
+    private:
+        std::vector<KeyValueTreeValue> values_;
+
+        friend class KeyValueTreeArrayBuilderBase;
+};
+
+class KeyValueTreeProperty
+{
+    public:
+        const std::string &key() const { return value_->first; }
+        const KeyValueTreeValue &value() const { return value_->second; }
+
+    private:
+        typedef std::map<std::string, KeyValueTreeValue>::const_iterator
+            IteratorType;
+
+        explicit KeyValueTreeProperty(IteratorType value) : value_(value) {}
+
+        IteratorType value_;
+
+        friend class KeyValueTreeObject;
+};
+
+class KeyValueTreeObject
+{
+    public:
+        KeyValueTreeObject() = default;
+        KeyValueTreeObject(const KeyValueTreeObject &other)
+        {
+            for (const auto &value : other.values_)
+            {
+                auto iter = valueMap_.insert(std::make_pair(value.key(), value.value())).first;
+                values_.push_back(KeyValueTreeProperty(iter));
+            }
+        }
+        KeyValueTreeObject &operator=(KeyValueTreeObject &other)
+        {
+            KeyValueTreeObject tmp(other);
+            std::swap(tmp.valueMap_, valueMap_);
+            std::swap(tmp.values_, values_);
+            return *this;
+        }
+        KeyValueTreeObject(KeyValueTreeObject &&)            = default;
+        KeyValueTreeObject &operator=(KeyValueTreeObject &&) = default;
+
+        const std::vector<KeyValueTreeProperty> &properties() const { return values_; }
+
+        bool keyExists(const std::string &key) const
+        {
+            return valueMap_.find(key) != valueMap_.end();
+        }
+        const KeyValueTreeValue &operator[](const std::string &key) const
+        {
+            return valueMap_.at(key);
+        }
+
+    private:
+        KeyValueTreeValue &operator[](const std::string &key)
+        {
+            return valueMap_.at(key);
+        }
+        std::map<std::string, KeyValueTreeValue>::iterator
+        addProperty(const std::string &key, KeyValueTreeValue &&value)
+        {
+            values_.reserve(values_.size() + 1);
+            auto iter = valueMap_.insert(std::make_pair(key, std::move(value))).first;
+            values_.push_back(KeyValueTreeProperty(iter));
+            return iter;
+        }
+
+        std::map<std::string, KeyValueTreeValue> valueMap_;
+        std::vector<KeyValueTreeProperty>        values_;
+
+        friend class KeyValueTreeObjectBuilder;
+};
+
+/********************************************************************
+ * Inline functions that could not be declared within the classes
+ */
+
+inline bool KeyValueTreeValue::isArray() const
+{
+    return value_.isType<KeyValueTreeArray>();
+}
+inline bool KeyValueTreeValue::isObject() const
+{
+    return value_.isType<KeyValueTreeObject>();
+}
+inline const KeyValueTreeArray &KeyValueTreeValue::asArray() const
+{
+    return value_.cast<KeyValueTreeArray>();
+}
+inline const KeyValueTreeObject &KeyValueTreeValue::asObject() const
+{
+    return value_.cast<KeyValueTreeObject>();
+}
+inline KeyValueTreeArray &KeyValueTreeValue::asArray()
+{
+    return value_.castRef<KeyValueTreeArray>();
+}
+inline KeyValueTreeObject &KeyValueTreeValue::asObject()
+{
+    return value_.castRef<KeyValueTreeObject>();
+}
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/utility/keyvaluetreebuilder.h b/src/gromacs/utility/keyvaluetreebuilder.h
new file mode 100644 (file)
index 0000000..f5856df
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares classes for building the data structures in keyvaluetree.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+#ifndef GMX_UTILITY_KEYVALUETREEBUILDER_H
+#define GMX_UTILITY_KEYVALUETREEBUILDER_H
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "gromacs/utility/keyvaluetree.h"
+#include "gromacs/utility/variant.h"
+
+namespace gmx
+{
+
+class KeyValueTreeArrayBuilder;
+class KeyValueTreeObjectBuilder;
+
+class KeyValueTreeBuilder
+{
+    public:
+        KeyValueTreeObjectBuilder rootObject();
+
+        KeyValueTreeObject build() { return std::move(root_); }
+
+    private:
+        template <typename T>
+        static KeyValueTreeValue createValue(const T &value)
+        {
+            return KeyValueTreeValue(Variant::create<T>(value));
+        }
+        template <typename T>
+        static KeyValueTreeValue createValue()
+        {
+            return KeyValueTreeValue(Variant::create<T>(T()));
+        }
+
+        KeyValueTreeObject root_;
+
+        friend class KeyValueTreeObjectArrayBuilder;
+        friend class KeyValueTreeObjectBuilder;
+        template <typename T>
+        friend class KeyValueTreeUniformArrayBuilder;
+};
+
+class KeyValueTreeValueBuilder
+{
+    public:
+        template <typename T>
+        void setValue(const T &value)
+        {
+            value_ = Variant::create<T>(value);
+        }
+        void setVariantValue(Variant &&value)
+        {
+            value_ = std::move(value);
+        }
+        KeyValueTreeObjectBuilder createObject();
+        KeyValueTreeArrayBuilder createArray();
+
+        KeyValueTreeValue build() { return KeyValueTreeValue(std::move(value_)); }
+
+    private:
+        Variant value_;
+};
+
+class KeyValueTreeArrayBuilderBase
+{
+    protected:
+        explicit KeyValueTreeArrayBuilderBase(KeyValueTreeArray *array)
+            : array_(array)
+        {
+        }
+
+        KeyValueTreeValue &addRawValue(Variant &&value)
+        {
+            KeyValueTreeValueBuilder builder;
+            builder.setVariantValue(std::move(value));
+            array_->values_.push_back(builder.build());
+            return array_->values_.back();
+        }
+        KeyValueTreeValue &addRawValue(KeyValueTreeValue &&value)
+        {
+            array_->values_.push_back(std::move(value));
+            return array_->values_.back();
+        }
+
+    private:
+        KeyValueTreeArray *array_;
+};
+
+class KeyValueTreeArrayBuilder : public KeyValueTreeArrayBuilderBase
+{
+    public:
+        using KeyValueTreeArrayBuilderBase::addRawValue;
+
+    private:
+        explicit KeyValueTreeArrayBuilder(KeyValueTreeArray *array)
+            : KeyValueTreeArrayBuilderBase(array)
+        {
+        }
+
+        friend class KeyValueTreeObjectBuilder;
+        friend class KeyValueTreeValueBuilder;
+};
+
+template <typename T>
+class KeyValueTreeUniformArrayBuilder : public KeyValueTreeArrayBuilderBase
+{
+    public:
+        void addValue(const T &value)
+        {
+            addRawValue(KeyValueTreeBuilder::createValue<T>(value));
+        }
+
+    private:
+        explicit KeyValueTreeUniformArrayBuilder(KeyValueTreeArray *array)
+            : KeyValueTreeArrayBuilderBase(array)
+        {
+        }
+
+        friend class KeyValueTreeObjectBuilder;
+};
+
+class KeyValueTreeObjectArrayBuilder : public KeyValueTreeArrayBuilderBase
+{
+    public:
+        KeyValueTreeObjectBuilder addObject();
+
+    private:
+        explicit KeyValueTreeObjectArrayBuilder(KeyValueTreeArray *array)
+            : KeyValueTreeArrayBuilderBase(array)
+        {
+        }
+
+        friend class KeyValueTreeObjectBuilder;
+};
+
+class KeyValueTreeObjectBuilder
+{
+    public:
+        void addRawValue(const std::string &key, KeyValueTreeValue &&value)
+        {
+            object_->addProperty(key, std::move(value));
+        }
+        void addRawValue(const std::string &key, Variant &&value)
+        {
+            object_->addProperty(key, KeyValueTreeValue(std::move(value)));
+        }
+        template <typename T>
+        void addValue(const std::string &key, const T &value)
+        {
+            addRawValue(key, KeyValueTreeBuilder::createValue<T>(value));
+        }
+        KeyValueTreeObjectBuilder addObject(const std::string &key)
+        {
+            auto iter = object_->addProperty(key, KeyValueTreeBuilder::createValue<KeyValueTreeObject>());
+            return KeyValueTreeObjectBuilder(&iter->second);
+        }
+        KeyValueTreeArrayBuilder addArray(const std::string &key)
+        {
+            auto iter = object_->addProperty(key, KeyValueTreeBuilder::createValue<KeyValueTreeArray>());
+            return KeyValueTreeArrayBuilder(&iter->second.asArray());
+        }
+        template <typename T>
+        KeyValueTreeUniformArrayBuilder<T> addUniformArray(const std::string &key)
+        {
+            auto iter = object_->addProperty(key, KeyValueTreeBuilder::createValue<KeyValueTreeArray>());
+            return KeyValueTreeUniformArrayBuilder<T>(&iter->second.asArray());
+        }
+        KeyValueTreeObjectArrayBuilder addObjectArray(const std::string &key)
+        {
+            auto iter = object_->addProperty(key, KeyValueTreeBuilder::createValue<KeyValueTreeArray>());
+            return KeyValueTreeObjectArrayBuilder(&iter->second.asArray());
+        }
+        void mergeObject(KeyValueTreeValue &&value)
+        {
+            KeyValueTreeObject &obj = value.asObject();
+            for (auto &prop : obj.valueMap_)
+            {
+                addRawValue(prop.first, std::move(prop.second));
+            }
+        }
+
+        bool keyExists(const std::string &key) const { return object_->keyExists(key); }
+        KeyValueTreeObjectBuilder getObject(const std::string &key) const
+        {
+            return KeyValueTreeObjectBuilder(&(*object_)[key].asObject());
+        }
+
+    private:
+        explicit KeyValueTreeObjectBuilder(KeyValueTreeObject *object)
+            : object_(object)
+        {
+        }
+        explicit KeyValueTreeObjectBuilder(KeyValueTreeValue *value)
+            : object_(&value->asObject())
+        {
+        }
+
+        KeyValueTreeObject *object_;
+
+        friend class KeyValueTreeBuilder;
+        friend class KeyValueTreeValueBuilder;
+        friend class KeyValueTreeObjectArrayBuilder;
+};
+
+/********************************************************************
+ * Inline functions that could not be declared within the classes
+ */
+
+inline KeyValueTreeObjectBuilder KeyValueTreeBuilder::rootObject()
+{
+    return KeyValueTreeObjectBuilder(&root_);
+}
+
+inline KeyValueTreeObjectBuilder KeyValueTreeValueBuilder::createObject()
+{
+    value_ = Variant::create<KeyValueTreeObject>(KeyValueTreeObject());
+    return KeyValueTreeObjectBuilder(&value_.castRef<KeyValueTreeObject>());
+}
+
+inline KeyValueTreeArrayBuilder KeyValueTreeValueBuilder::createArray()
+{
+    value_ = Variant::create<KeyValueTreeArray>(KeyValueTreeArray());
+    return KeyValueTreeArrayBuilder(&value_.castRef<KeyValueTreeArray>());
+}
+
+inline KeyValueTreeObjectBuilder KeyValueTreeObjectArrayBuilder::addObject()
+{
+    auto &value = addRawValue(KeyValueTreeBuilder::createValue<KeyValueTreeObject>());
+    return KeyValueTreeObjectBuilder(&value);
+}
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/utility/keyvaluetreeserializer.cpp b/src/gromacs/utility/keyvaluetreeserializer.cpp
new file mode 100644 (file)
index 0000000..df8bda3
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+#include "gmxpre.h"
+
+#include "keyvaluetreeserializer.h"
+
+#include "gromacs/utility/iserializer.h"
+#include "gromacs/utility/keyvaluetree.h"
+#include "gromacs/utility/keyvaluetreebuilder.h"
+#include "gromacs/utility/mutex.h"
+
+namespace gmx
+{
+
+namespace
+{
+
+class ValueSerializer
+{
+    public:
+        static void initSerializers();
+
+        static void serialize(const KeyValueTreeValue &value, ISerializer *serializer);
+        static KeyValueTreeValue deserialize(ISerializer *serializer);
+
+    private:
+        ValueSerializer();
+
+        typedef void (*SerializerFunction)(const KeyValueTreeValue &value, ISerializer *serializer);
+        typedef void (*DeserializerFunction)(KeyValueTreeValueBuilder *builder, ISerializer *serializer);
+
+        struct Serializer
+        {
+            unsigned char         typeTag;
+            SerializerFunction    serialize;
+            DeserializerFunction  deserialize;
+        };
+
+        static Mutex                                         s_initMutex;
+        static std::map<std::type_index, Serializer>         s_serializers;
+        static std::map<unsigned char, DeserializerFunction> s_deserializers;
+};
+
+Mutex                                                          ValueSerializer::s_initMutex;
+std::map<std::type_index, ValueSerializer::Serializer>         ValueSerializer::s_serializers;
+std::map<unsigned char, ValueSerializer::DeserializerFunction> ValueSerializer::s_deserializers;
+
+template <typename T>
+struct SerializationTraits
+{
+};
+
+template <>
+struct SerializationTraits<KeyValueTreeObject>
+{
+    static void serialize(const KeyValueTreeObject &value, ISerializer *serializer)
+    {
+        int         count = value.properties().size();
+        serializer->doInt(&count);
+        for (const auto &prop : value.properties())
+        {
+            serializer->doString(const_cast<std::string *>(&prop.key()));
+            ValueSerializer::serialize(prop.value(), serializer);
+        }
+    }
+    static void deserialize(KeyValueTreeValueBuilder *value, ISerializer *serializer)
+    {
+        KeyValueTreeObjectBuilder builder(value->createObject());
+        deserializeObject(&builder, serializer);
+    }
+    static void deserializeObject(KeyValueTreeObjectBuilder *builder, ISerializer *serializer)
+    {
+        int         count;
+        std::string key;
+        serializer->doInt(&count);
+        for (int i = 0; i < count; ++i)
+        {
+            serializer->doString(&key);
+            builder->addRawValue(key, ValueSerializer::deserialize(serializer));
+        }
+    }
+};
+
+template <>
+struct SerializationTraits<KeyValueTreeArray>
+{
+    static void serialize(const KeyValueTreeArray &array, ISerializer *serializer)
+    {
+        int         count = array.values().size();
+        serializer->doInt(&count);
+        for (const auto &value : array.values())
+        {
+            ValueSerializer::serialize(value, serializer);
+        }
+    }
+    static void deserialize(KeyValueTreeValueBuilder *value, ISerializer *serializer)
+    {
+        KeyValueTreeArrayBuilder builder(value->createArray());
+        int                      count;
+        serializer->doInt(&count);
+        for (int i = 0; i < count; ++i)
+        {
+            builder.addRawValue(ValueSerializer::deserialize(serializer));
+        }
+    }
+};
+
+template <>
+struct SerializationTraits<std::string>
+{
+    static void serialize(const std::string &value, ISerializer *serializer)
+    {
+        serializer->doString(const_cast<std::string *>(&value));
+    }
+    static void deserialize(KeyValueTreeValueBuilder *builder, ISerializer *serializer)
+    {
+        std::string value;
+        serializer->doString(&value);
+        builder->setValue<std::string>(value);
+    }
+};
+
+template <>
+struct SerializationTraits<int>
+{
+    static void serialize(int value, ISerializer *serializer)
+    {
+        serializer->doInt(&value);
+    }
+    static void deserialize(KeyValueTreeValueBuilder *builder, ISerializer *serializer)
+    {
+        int value;
+        serializer->doInt(&value);
+        builder->setValue<int>(value);
+    }
+};
+
+template <>
+struct SerializationTraits<float>
+{
+    static void serialize(float value, ISerializer *serializer)
+    {
+        serializer->doFloat(&value);
+    }
+    static void deserialize(KeyValueTreeValueBuilder *builder, ISerializer *serializer)
+    {
+        float value;
+        serializer->doFloat(&value);
+        builder->setValue<float>(value);
+    }
+};
+
+template <>
+struct SerializationTraits<double>
+{
+    static void serialize(double value, ISerializer *serializer)
+    {
+        serializer->doDouble(&value);
+    }
+    static void deserialize(KeyValueTreeValueBuilder *builder, ISerializer *serializer)
+    {
+        double value;
+        serializer->doDouble(&value);
+        builder->setValue<double>(value);
+    }
+};
+
+//! Helper function for serializing values of a certain type.
+template <typename T>
+void serializeValueType(const KeyValueTreeValue &value, ISerializer *serializer)
+{
+    SerializationTraits<T>::serialize(value.cast<T>(), serializer);
+}
+
+#define SERIALIZER(tag, type) \
+    { std::type_index(typeid(type)), \
+      { tag, &serializeValueType<type>, &SerializationTraits<type>::deserialize } \
+    }
+
+// static
+void ValueSerializer::initSerializers()
+{
+    lock_guard<Mutex> lock(s_initMutex);
+    if (!s_serializers.empty())
+    {
+        return;
+    }
+    s_serializers = {
+        SERIALIZER('O', KeyValueTreeObject),
+        SERIALIZER('A', KeyValueTreeArray),
+        SERIALIZER('s', std::string),
+        SERIALIZER('i', int),
+        SERIALIZER('f', float),
+        SERIALIZER('d', double),
+    };
+    for (const auto item : s_serializers)
+    {
+        s_deserializers[item.second.typeTag] = item.second.deserialize;
+    }
+}
+
+void ValueSerializer::serialize(const KeyValueTreeValue &value, ISerializer *serializer)
+{
+    auto iter = s_serializers.find(value.type());
+    GMX_RELEASE_ASSERT(iter != s_serializers.end(),
+                       "Unknown value type for serializization");
+    unsigned char typeTag = iter->second.typeTag;
+    serializer->doUChar(&typeTag);
+    iter->second.serialize(value, serializer);
+}
+
+KeyValueTreeValue ValueSerializer::deserialize(ISerializer *serializer)
+{
+    unsigned char typeTag;
+    serializer->doUChar(&typeTag);
+    auto          iter = s_deserializers.find(typeTag);
+    GMX_RELEASE_ASSERT(iter != s_deserializers.end(),
+                       "Unknown type tag for deserializization");
+    KeyValueTreeValueBuilder builder;
+    iter->second(&builder, serializer);
+    return builder.build();
+}
+
+}   // namespace
+
+//! \cond libapi
+void serializeKeyValueTree(const KeyValueTreeObject &root, ISerializer *serializer)
+{
+    GMX_RELEASE_ASSERT(!serializer->reading(),
+                       "Incorrect serializer direction");
+    ValueSerializer::initSerializers();
+    SerializationTraits<KeyValueTreeObject>::serialize(root, serializer);
+}
+
+KeyValueTreeObject deserializeKeyValueTree(ISerializer *serializer)
+{
+    GMX_RELEASE_ASSERT(serializer->reading(),
+                       "Incorrect serializer direction");
+    ValueSerializer::initSerializers();
+    KeyValueTreeBuilder       builder;
+    KeyValueTreeObjectBuilder obj(builder.rootObject());
+    SerializationTraits<KeyValueTreeObject>::deserializeObject(&obj, serializer);
+    return builder.build();
+}
+//! \endcond
+
+} // namespace gmx
diff --git a/src/gromacs/utility/keyvaluetreeserializer.h b/src/gromacs/utility/keyvaluetreeserializer.h
new file mode 100644 (file)
index 0000000..0cbbb2c
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares serialization routines for KeyValueTree objects.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+#ifndef GMX_UTILITY_KEYVALUETREESERIALIZER_H
+#define GMX_UTILITY_KEYVALUETREESERIALIZER_H
+
+namespace gmx
+{
+
+class KeyValueTreeObject;
+class ISerializer;
+
+//! \cond libapi
+/*! \brief
+ * Serializes a KeyValueTreeObject with given serializer.
+ *
+ * \ingroup module_utility
+ */
+void serializeKeyValueTree(const KeyValueTreeObject &root, ISerializer *serializer);
+/*! \brief
+ * Deserializes a KeyValueTreeObject from a given serializer.
+ *
+ * \ingroup module_utility
+ */
+KeyValueTreeObject deserializeKeyValueTree(ISerializer *serializer);
+//! \endcond
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/utility/keyvaluetreetransform.cpp b/src/gromacs/utility/keyvaluetreetransform.cpp
new file mode 100644 (file)
index 0000000..cf80b37
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+#include "gmxpre.h"
+
+#include "keyvaluetreetransform.h"
+
+#include <functional>
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/ikeyvaluetreeerror.h"
+#include "gromacs/utility/keyvaluetreebuilder.h"
+#include "gromacs/utility/stringcompare.h"
+#include "gromacs/utility/stringutil.h"
+
+namespace gmx
+{
+
+/********************************************************************
+ * IKeyValueTreeTransformRules
+ */
+
+IKeyValueTreeTransformRules::~IKeyValueTreeTransformRules()
+{
+}
+
+/********************************************************************
+ * IKeyValueTreeBackMapping
+ */
+
+IKeyValueTreeBackMapping::~IKeyValueTreeBackMapping()
+{
+}
+
+namespace
+{
+
+class KeyValueTreeBackMapping : public IKeyValueTreeBackMapping
+{
+    public:
+        class Entry
+        {
+            public:
+                Entry() = default;
+                explicit Entry(const KeyValueTreePath &path) : sourcePath_(path) {}
+
+                Entry *getOrCreateChildEntry(const std::string &key)
+                {
+                    auto iter = childEntries_.find(key);
+                    if (iter == childEntries_.end())
+                    {
+                        iter = childEntries_.insert(std::make_pair(key, Entry())).first;
+                    }
+                    return &iter->second;
+                }
+                void setMapping(const KeyValueTreePath  &path,
+                                const KeyValueTreeValue &value)
+                {
+                    if (value.isObject())
+                    {
+                        const KeyValueTreeObject &object = value.asObject();
+                        for (const auto &prop : object.properties())
+                        {
+                            childEntries_[prop.key()] = Entry(path);
+                        }
+                    }
+                    else
+                    {
+                        sourcePath_ = path;
+                    }
+                }
+
+                KeyValueTreePath             sourcePath_;
+                std::map<std::string, Entry> childEntries_;
+        };
+
+        virtual KeyValueTreePath
+        originalPath(const KeyValueTreePath &path) const
+        {
+            const Entry *entry = &rootEntry_;
+            for (const auto &element : path.elements())
+            {
+                auto iter = entry->childEntries_.find(element);
+                if (iter == entry->childEntries_.end())
+                {
+                    break;
+                }
+                entry = &iter->second;
+            }
+            GMX_RELEASE_ASSERT(entry->childEntries_.empty()
+                               && !entry->sourcePath_.empty(),
+                               "Requested path not uniquely mapped");
+            return entry->sourcePath_;
+        }
+
+        Entry *rootEntry() { return &rootEntry_; }
+
+    private:
+        Entry rootEntry_;
+};
+
+}   // namespace
+
+namespace internal
+{
+
+/********************************************************************
+ * KeyValueTreeTransformerImpl
+ */
+
+class KeyValueTreeTransformerImpl : public IKeyValueTreeTransformRules
+{
+    public:
+        class Rule
+        {
+            public:
+                typedef std::function<void(KeyValueTreeValueBuilder *, const KeyValueTreeValue &)>
+                    TransformFunction;
+                typedef std::map<std::string, Rule, StringCompare> ChildRuleMap;
+
+                explicit Rule(StringCompareType keyMatchType)
+                    : childRules_(keyMatchType)
+                {
+                }
+
+                const Rule *findMatchingChildRule(const std::string &key) const
+                {
+                    auto iter = childRules_.find(key);
+                    if (iter == childRules_.end())
+                    {
+                        return nullptr;
+                    }
+                    return &iter->second;
+                }
+                Rule *getOrCreateChildRule(const std::string &key)
+                {
+                    auto iter = childRules_.find(key);
+                    if (iter == childRules_.end())
+                    {
+                        return createChildRule(key, StringCompareType::Exact);
+                    }
+                    return &iter->second;
+                }
+                Rule *createChildRule(const std::string &key,
+                                      StringCompareType  keyMatchType)
+                {
+                    auto result = childRules_.insert(std::make_pair(key, Rule(keyMatchType)));
+                    GMX_RELEASE_ASSERT(result.second,
+                                       "Cannot specify key match type after child rules");
+                    return &result.first->second;
+                }
+
+                void collectMappedPaths(const KeyValueTreePath        &prefix,
+                                        std::vector<KeyValueTreePath> *result) const
+                {
+                    for (const auto &value : childRules_)
+                    {
+                        KeyValueTreePath path = prefix;
+                        path.append(value.first);
+                        const Rule      &rule = value.second;
+                        if (rule.transform_)
+                        {
+                            result->push_back(path);
+                        }
+                        else
+                        {
+                            rule.collectMappedPaths(path, result);
+                        }
+                    }
+                }
+
+                KeyValueTreePath            targetPath_;
+                std::string                 targetKey_;
+                TransformFunction           transform_;
+                ChildRuleMap                childRules_;
+        };
+
+        class Transformer
+        {
+            public:
+                explicit Transformer(IKeyValueTreeErrorHandler *errorHandler)
+                    : errorHandler_(errorHandler),
+                      backMapping_(new KeyValueTreeBackMapping)
+                {
+                    if (errorHandler_ == nullptr)
+                    {
+                        errorHandler_ = defaultKeyValueTreeErrorHandler();
+                    }
+                }
+
+                void transform(const Rule *rootRule, const KeyValueTreeObject &tree)
+                {
+                    if (rootRule != nullptr)
+                    {
+                        doChildTransforms(rootRule, tree);
+                    }
+                }
+
+                KeyValueTreeTransformResult result()
+                {
+                    return KeyValueTreeTransformResult(builder_.build(),
+                                                       std::move(backMapping_));
+                }
+
+            private:
+                void doTransform(const Rule *rule, const KeyValueTreeValue &value);
+                void doChildTransforms(const Rule *rule, const KeyValueTreeObject &object);
+                void applyTransformedValue(const Rule *rule, KeyValueTreeValue &&value);
+
+                IKeyValueTreeErrorHandler               *errorHandler_;
+                KeyValueTreeBuilder                      builder_;
+                std::unique_ptr<KeyValueTreeBackMapping> backMapping_;
+                KeyValueTreePath                         context_;
+        };
+
+        virtual KeyValueTreeTransformRuleBuilder addRule()
+        {
+            return KeyValueTreeTransformRuleBuilder(this);
+        }
+
+        Rule *getOrCreateRootRule()
+        {
+            if (rootRule_ == nullptr)
+            {
+                createRootRule(StringCompareType::Exact);
+            }
+            return rootRule_.get();
+        }
+        void createRootRule(StringCompareType keyMatchType)
+        {
+            GMX_RELEASE_ASSERT(rootRule_ == nullptr,
+                               "Cannot specify key match type after child rules");
+            rootRule_.reset(new Rule(keyMatchType));
+        }
+
+        std::unique_ptr<Rule>  rootRule_;
+};
+
+/********************************************************************
+ * KeyValueTreeTransformerImpl::Transformer
+ */
+
+void KeyValueTreeTransformerImpl::Transformer::doTransform(
+        const Rule *rule, const KeyValueTreeValue &value)
+{
+    if (rule->transform_)
+    {
+        KeyValueTreeValueBuilder valueBuilder;
+        try
+        {
+            rule->transform_(&valueBuilder, value);
+        }
+        catch (UserInputError &ex)
+        {
+            if (!errorHandler_->onError(&ex, context_))
+            {
+                throw;
+            }
+            return;
+        }
+        applyTransformedValue(rule, valueBuilder.build());
+        return;
+    }
+    if (!rule->childRules_.empty())
+    {
+        doChildTransforms(rule, value.asObject());
+    }
+}
+
+void KeyValueTreeTransformerImpl::Transformer::doChildTransforms(
+        const Rule *rule, const KeyValueTreeObject &object)
+{
+    for (const auto &prop : object.properties())
+    {
+        const Rule *childRule = rule->findMatchingChildRule(prop.key());
+        if (childRule != nullptr)
+        {
+            context_.append(prop.key());
+            doTransform(childRule, prop.value());
+            context_.pop_back();
+        }
+    }
+}
+
+void KeyValueTreeTransformerImpl::Transformer::applyTransformedValue(
+        const Rule *rule, KeyValueTreeValue &&value)
+{
+    KeyValueTreeObjectBuilder       objBuilder = builder_.rootObject();
+    KeyValueTreeBackMapping::Entry *mapEntry   = backMapping_->rootEntry();
+    for (const std::string &key : rule->targetPath_.elements())
+    {
+        if (objBuilder.keyExists(key))
+        {
+            objBuilder = objBuilder.getObject(key);
+        }
+        else
+        {
+            objBuilder = objBuilder.addObject(key);
+        }
+        mapEntry = mapEntry->getOrCreateChildEntry(key);
+    }
+    mapEntry = mapEntry->getOrCreateChildEntry(rule->targetKey_);
+    mapEntry->setMapping(context_, value);
+    if (objBuilder.keyExists(rule->targetKey_))
+    {
+        objBuilder.getObject(rule->targetKey_).mergeObject(std::move(value));
+    }
+    else
+    {
+        objBuilder.addRawValue(rule->targetKey_, std::move(value));
+    }
+}
+
+}   // namespace internal
+
+/********************************************************************
+ * KeyValueTreeTransformer
+ */
+
+KeyValueTreeTransformer::KeyValueTreeTransformer()
+    : impl_(new internal::KeyValueTreeTransformerImpl)
+{
+}
+
+KeyValueTreeTransformer::~KeyValueTreeTransformer()
+{
+}
+
+IKeyValueTreeTransformRules *KeyValueTreeTransformer::rules()
+{
+    return impl_.get();
+}
+
+std::vector<KeyValueTreePath> KeyValueTreeTransformer::mappedPaths() const
+{
+    std::vector<KeyValueTreePath> result;
+    if (impl_->rootRule_)
+    {
+        impl_->rootRule_->collectMappedPaths(KeyValueTreePath(), &result);
+    }
+    return result;
+}
+
+KeyValueTreeTransformResult
+KeyValueTreeTransformer::transform(const KeyValueTreeObject  &tree,
+                                   IKeyValueTreeErrorHandler *errorHandler) const
+{
+    internal::KeyValueTreeTransformerImpl::Transformer transformer(errorHandler);
+    transformer.transform(impl_->rootRule_.get(), tree);
+    return transformer.result();
+}
+
+/********************************************************************
+ * KeyValueTreeTransformRuleBuilder::Data
+ */
+
+class KeyValueTreeTransformRuleBuilder::Data
+{
+    public:
+        typedef internal::KeyValueTreeTransformerImpl::Rule Rule;
+
+        Data() : keyMatchType_(StringCompareType::Exact) {}
+
+        void createRule(internal::KeyValueTreeTransformerImpl *impl)
+        {
+            if (toPath_.empty())
+            {
+                createRuleWithKeyMatchType(impl);
+                return;
+            }
+            Rule *rule = impl->getOrCreateRootRule();
+            for (const std::string &key : fromPath_.elements())
+            {
+                rule = rule->getOrCreateChildRule(key);
+            }
+            rule->targetKey_  = toPath_.pop_last();
+            rule->targetPath_ = std::move(toPath_);
+            rule->transform_  = transform_;
+        }
+
+        void createRuleWithKeyMatchType(internal::KeyValueTreeTransformerImpl *impl)
+        {
+            if (fromPath_.empty())
+            {
+                impl->createRootRule(keyMatchType_);
+            }
+            else
+            {
+                std::string lastKey = fromPath_.pop_last();
+                Rule       *rule    = impl->getOrCreateRootRule();
+                for (const std::string &key : fromPath_.elements())
+                {
+                    rule = rule->getOrCreateChildRule(key);
+                }
+                rule->createChildRule(lastKey, keyMatchType_);
+            }
+        }
+
+        KeyValueTreePath         fromPath_;
+        KeyValueTreePath         toPath_;
+        Rule::TransformFunction  transform_;
+        StringCompareType        keyMatchType_;
+};
+
+/********************************************************************
+ * KeyValueTreeTransformRuleBuilder
+ */
+
+KeyValueTreeTransformRuleBuilder::KeyValueTreeTransformRuleBuilder(
+        internal::KeyValueTreeTransformerImpl *impl)
+    : impl_(impl), data_(new Data)
+{
+}
+
+KeyValueTreeTransformRuleBuilder::~KeyValueTreeTransformRuleBuilder()
+{
+    if (!std::uncaught_exception())
+    {
+        data_->createRule(impl_);
+    }
+}
+
+void KeyValueTreeTransformRuleBuilder::setFromPath(const std::string &path)
+{
+    data_->fromPath_ = path;
+}
+
+void KeyValueTreeTransformRuleBuilder::setToPath(const std::string &path)
+{
+    data_->toPath_ = path;
+}
+
+void KeyValueTreeTransformRuleBuilder::setKeyMatchType(StringCompareType keyMatchType)
+{
+    data_->keyMatchType_ = keyMatchType;
+}
+
+void KeyValueTreeTransformRuleBuilder::addTransformToVariant(
+        std::function<Variant(const Variant &)> transform)
+{
+    data_->transform_ =
+        [transform] (KeyValueTreeValueBuilder *builder, const KeyValueTreeValue &value)
+        {
+            builder->setVariantValue(transform(value.asVariant()));
+        };
+}
+
+void KeyValueTreeTransformRuleBuilder::addTransformToObject(
+        std::function<void(KeyValueTreeObjectBuilder *, const Variant &)> transform)
+{
+    data_->transform_ =
+        [transform] (KeyValueTreeValueBuilder *builder, const KeyValueTreeValue &value)
+        {
+            KeyValueTreeObjectBuilder obj = builder->createObject();
+            transform(&obj, value.asVariant());
+        };
+}
+
+} // namespace gmx
diff --git a/src/gromacs/utility/keyvaluetreetransform.h b/src/gromacs/utility/keyvaluetreetransform.h
new file mode 100644 (file)
index 0000000..68f121f
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares utilities for transforming key-value trees.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+#ifndef GMX_UTILITY_KEYVALUETREETRANSFORM_H
+#define GMX_UTILITY_KEYVALUETREETRANSFORM_H
+
+#include <functional>
+#include <string>
+#include <vector>
+
+#include "gromacs/utility/classhelpers.h"
+#include "gromacs/utility/keyvaluetree.h"
+#include "gromacs/utility/variant.h"
+
+namespace gmx
+{
+
+class IKeyValueTreeErrorHandler;
+class KeyValueTreeObjectBuilder;
+
+enum class StringCompareType;
+
+class KeyValueTreeTransformRuleBuilder;
+
+namespace internal
+{
+class KeyValueTreeTransformerImpl;
+}
+
+class IKeyValueTreeTransformRules
+{
+    public:
+        virtual KeyValueTreeTransformRuleBuilder addRule() = 0;
+
+    protected:
+        ~IKeyValueTreeTransformRules();
+};
+
+class IKeyValueTreeBackMapping
+{
+    public:
+        virtual ~IKeyValueTreeBackMapping();
+
+        virtual KeyValueTreePath
+        originalPath(const KeyValueTreePath &path) const = 0;
+};
+
+class KeyValueTreeTransformResult
+{
+    public:
+        KeyValueTreeObject object() { return std::move(object_); }
+        const IKeyValueTreeBackMapping &backMapping() const { return *mapping_; }
+
+    private:
+        typedef std::unique_ptr<IKeyValueTreeBackMapping> MappingPointer;
+
+        KeyValueTreeTransformResult(KeyValueTreeObject &&object,
+                                    MappingPointer     &&mapping)
+            : object_(std::move(object)), mapping_(std::move(mapping))
+        {
+        }
+
+        KeyValueTreeObject                         object_;
+        std::unique_ptr<IKeyValueTreeBackMapping>  mapping_;
+
+        friend class internal::KeyValueTreeTransformerImpl;
+};
+
+class KeyValueTreeTransformer
+{
+    public:
+        KeyValueTreeTransformer();
+        ~KeyValueTreeTransformer();
+
+        IKeyValueTreeTransformRules *rules();
+
+        std::vector<KeyValueTreePath> mappedPaths() const;
+
+        KeyValueTreeTransformResult
+        transform(const KeyValueTreeObject  &tree,
+                  IKeyValueTreeErrorHandler *errorHandler) const;
+
+    private:
+        PrivateImplPointer<internal::KeyValueTreeTransformerImpl> impl_;
+};
+
+class KeyValueTreeTransformRuleBuilder
+{
+    public:
+        class Base
+        {
+            protected:
+                explicit Base(KeyValueTreeTransformRuleBuilder *builder)
+                    : builder_(builder)
+                {
+                }
+
+                KeyValueTreeTransformRuleBuilder *builder_;
+        };
+
+        template <typename FromType, typename ToType>
+        class ToValue : public Base
+        {
+            public:
+                explicit ToValue(KeyValueTreeTransformRuleBuilder *builder)
+                    : Base(builder)
+                {
+                }
+
+                void transformWith(std::function<ToType(const FromType &)> transform)
+                {
+                    builder_->addTransformToVariant(
+                            [transform] (const Variant &value)
+                            {
+                                return Variant::create<ToType>(transform(value.cast<FromType>()));
+                            });
+                }
+        };
+
+        template <typename FromType>
+        class ToObject : public Base
+        {
+            public:
+                explicit ToObject(KeyValueTreeTransformRuleBuilder *builder)
+                    : Base(builder)
+                {
+                }
+
+                void transformWith(std::function<void(KeyValueTreeObjectBuilder *, const FromType &)> transform)
+                {
+                    builder_->addTransformToObject(
+                            [transform] (KeyValueTreeObjectBuilder *builder, const Variant &value)
+                            {
+                                transform(builder, value.cast<FromType>());
+                            });
+                }
+        };
+
+        template <typename FromType>
+        class AfterFrom : public Base
+        {
+            public:
+                explicit AfterFrom(KeyValueTreeTransformRuleBuilder *builder)
+                    : Base(builder)
+                {
+                }
+
+                template <typename ToType>
+                ToValue<FromType, ToType> to(const std::string &path)
+                {
+                    builder_->setToPath(path);
+                    return ToValue<FromType, ToType>(builder_);
+                }
+
+                ToObject<FromType> toObject(const std::string &path)
+                {
+                    builder_->setToPath(path);
+                    return ToObject<FromType>(builder_);
+                }
+        };
+
+        explicit KeyValueTreeTransformRuleBuilder(internal::KeyValueTreeTransformerImpl *impl);
+        KeyValueTreeTransformRuleBuilder(KeyValueTreeTransformRuleBuilder &&)            = default;
+        KeyValueTreeTransformRuleBuilder &operator=(KeyValueTreeTransformRuleBuilder &&) = default;
+        ~KeyValueTreeTransformRuleBuilder();
+
+        template <typename FromType>
+        AfterFrom<FromType> from(const std::string &path)
+        {
+            setFromPath(path);
+            return AfterFrom<FromType>(this);
+        }
+        void keyMatchType(const std::string &path, StringCompareType keyMatchType)
+        {
+            setFromPath(path);
+            setKeyMatchType(keyMatchType);
+        }
+
+    private:
+        void setFromPath(const std::string &path);
+        void setToPath(const std::string &path);
+        void setKeyMatchType(StringCompareType keyMatchType);
+        void addTransformToVariant(std::function<Variant(const Variant &)> transform);
+        void addTransformToObject(std::function<void(KeyValueTreeObjectBuilder *, const Variant &)> transform);
+
+        class Data;
+
+        internal::KeyValueTreeTransformerImpl *impl_;
+        std::unique_ptr<Data>                  data_;
+};
+
+} // namespace gmx
+
+#endif
similarity index 60%
rename from src/gromacs/gmxlib/md_logging.cpp
rename to src/gromacs/utility/logger.cpp
index a114643162e7eb83c4d5a06039fbedf850afc9a1..7be58088b45acc62a9f1626c830a2d3442f180c2 100644 (file)
@@ -1,9 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2012,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  */
 #include "gmxpre.h"
 
-#include "md_logging.h"
+#include "logger.h"
 
 #include <cstdarg>
-#include <cstdio>
 
-#include "gromacs/mdtypes/commrec.h"
+#include "gromacs/utility/stringutil.h"
 
-
-void md_print_info(const t_commrec *cr, FILE *fplog,
-                   const char *fmt, ...)
+namespace gmx
 {
-    va_list ap;
 
-    if (cr == NULL || SIMMASTER(cr))
-    {
-        va_start(ap, fmt);
-
-        vfprintf(stderr, fmt, ap);
+namespace
+{
 
-        va_end(ap);
-    }
-    if (fplog != NULL)
-    {
-        va_start(ap, fmt);
+//! Helper method for reading logging targets from an array.
+ILogTarget *getTarget(ILogTarget        *targets[MDLogger::LogLevelCount],
+                      MDLogger::LogLevel level)
+{
+    return targets[static_cast<int>(level)];
+}
 
-        vfprintf(fplog, fmt, ap);
+}   // namespace
 
-        va_end(ap);
-    }
+ILogTarget::~ILogTarget()
+{
 }
 
-void md_print_warn(const t_commrec *cr, FILE *fplog,
-                   const char *fmt, ...)
+
+LogEntryWriter &LogEntryWriter::appendTextFormatted(const char *fmt, ...)
 {
     va_list ap;
 
-    if (cr == NULL || SIMMASTER(cr))
-    {
-        va_start(ap, fmt);
-
-        fprintf(stderr, "\n");
-        vfprintf(stderr, fmt, ap);
-        fprintf(stderr, "\n");
-
-        va_end(ap);
-    }
-    if (fplog != NULL)
-    {
-        va_start(ap, fmt);
+    va_start(ap, fmt);
+    entry_.text.append(formatStringV(fmt, ap));
+    va_end(ap);
+    return *this;
+}
 
-        fprintf(fplog, "\n");
-        vfprintf(fplog, fmt, ap);
-        fprintf(fplog, "\n");
+MDLogger::MDLogger()
+    : warning(nullptr), info(nullptr)
+{
+}
 
-        va_end(ap);
-    }
+MDLogger::MDLogger(ILogTarget *targets[LogLevelCount])
+    : warning(getTarget(targets, LogLevel::Warning)),
+      info(getTarget(targets, LogLevel::Info))
+{
 }
+
+} // namespace gmx
diff --git a/src/gromacs/utility/logger.h b/src/gromacs/utility/logger.h
new file mode 100644 (file)
index 0000000..f9f4f6d
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares functionality for logging.
+ *
+ * See \ref page_logging for an overview of the functionality.
+ *
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+#ifndef GMX_UTILITY_LOGGER_H
+#define GMX_UTILITY_LOGGER_H
+
+#include <string>
+
+namespace gmx
+{
+
+struct LogEntry
+{
+    LogEntry() : asParagraph(false) {}
+
+    std::string text;
+    bool        asParagraph;
+};
+
+/*! \libinternal \brief
+ * Target where log output can be written.
+ *
+ * \ingroup module_utility
+ */
+class ILogTarget
+{
+    public:
+        virtual ~ILogTarget();
+
+        //! Writes a log entry to this target.
+        virtual void writeEntry(const LogEntry &entry) = 0;
+};
+
+/*! \libinternal \brief
+ * Helper class for creating log entries with ::GMX_LOG.
+ *
+ * \ingroup module_utility
+ */
+class LogEntryWriter
+{
+    public:
+        //! Appends given text to the log entry.
+        LogEntryWriter &appendText(const char *text)
+        {
+            entry_.text.append(text);
+            return *this;
+        }
+        //! Appends given text to the log entry.
+        LogEntryWriter &appendText(const std::string &text)
+        {
+            entry_.text.append(text);
+            return *this;
+        }
+        //! Appends given text to the log entry, with printf-style formatting.
+        LogEntryWriter &appendTextFormatted(const char *fmt, ...);
+        //! Writes the log entry with empty lines before and after.
+        LogEntryWriter &asParagraph()
+        {
+            entry_.asParagraph = true;
+            return *this;
+        }
+
+    private:
+        LogEntry    entry_;
+
+        friend class LogWriteHelper;
+};
+
+/*! \internal \brief
+ * Helper class for implementing ::GMX_LOG.
+ *
+ * \ingroup module_utility
+ */
+class LogWriteHelper
+{
+    public:
+        //! Initializes a helper for writing to the given target.
+        explicit LogWriteHelper(ILogTarget *target) : target_(target) {}
+
+        // Should be explicit, once that works in CUDA.
+        /*! \brief
+         * Returns whether anything needs to be written.
+         *
+         * Note that the return value is unintuitively `false` when the target
+         * is active, to allow implementing ::GMX_LOG like it is now.
+         */
+        operator bool() const { return target_ == NULL; }
+
+        /*! \brief
+         * Writes the entry from the given writer to the log target.
+         *
+         * This is implemented as an assignment operator to get proper
+         * precedence for operations for the ::GMX_LOG macro; this is a common
+         * technique for implementing macros that allow streming information to
+         * them (see, e.g., Google Test).
+         */
+        void operator=(const LogEntryWriter &entryWriter)
+        {
+            target_->writeEntry(entryWriter.entry_);
+        }
+
+    private:
+        ILogTarget *target_;
+};
+
+/*! \libinternal \brief
+ * Represents a single logging level.
+ *
+ * Typically this type is not used directly, but instances in MDLogger are
+ * simply accessed through ::GMX_LOG in code that writes to the log.
+ *
+ * \ingroup module_utility
+ */
+class LogLevelHelper
+{
+    public:
+        //! Initializes a helper for writing to the given target.
+        explicit LogLevelHelper(ILogTarget *target) : target_(target) {}
+
+        // Both of the below should be explicit, once that works in CUDA.
+        //! Returns whether the output for this log level goes anywhere.
+        operator bool() const { return target_ != NULL; }
+
+        //! Creates a helper for ::GMX_LOG.
+        operator LogWriteHelper() const { return LogWriteHelper(target_); }
+
+    private:
+        ILogTarget *target_;
+};
+
+/*! \libinternal \brief
+ * Declares a logging interface.
+ *
+ * Typically, this object is not created directly, but instead through
+ * LoggerBuilder.
+ *
+ * For now, this is named MDLogger, since it is used only there, and it is not
+ * clear whether the logging levels can be the same throughout the code.  It
+ * should be relatively straightforward to split this into multiple classes
+ * with different supported logging levels without changing calling code, or to
+ * rename it to Logger if we do not need any specialization.
+ *
+ * \ingroup module_utility
+ */
+class MDLogger
+{
+    public:
+        //! Supported logging levels.
+        enum LogLevel
+        {
+            Warning,
+            Info
+        };
+        //! Number of logging levels.
+        static const int LogLevelCount = static_cast<int>(Info) + 1;
+
+        MDLogger();
+        //! Creates a logger with the given targets.
+        explicit MDLogger(ILogTarget *targets[LogLevelCount]);
+
+        //! For writing at LogLevel::Warning level.
+        LogLevelHelper warning;
+        //! For writing at LogLevel::Info level.
+        LogLevelHelper info;
+};
+
+/*! \brief
+ * Helper to log information using gmx::MDLogger.
+ *
+ * \param  logger  LogLevelHelper instance to use for logging.
+ *
+ * Used as
+ * \code
+   GMX_LOG(logger.warning).appendText(...);
+   \endcode
+ * and ensures that the code to format the output is only executed when the
+ * output goes somewhere.
+ *
+ * See LogEntryWriter for functions that can be used with the macro (such as
+ * the appendText() in the example).
+ *
+ * \ingroup module_utility
+ */
+#define GMX_LOG(logger) \
+    if (::gmx::LogWriteHelper helper = ::gmx::LogWriteHelper(logger)) { } else \
+        helper = ::gmx::LogEntryWriter()
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/utility/loggerbuilder.cpp b/src/gromacs/utility/loggerbuilder.cpp
new file mode 100644 (file)
index 0000000..a5da7d0
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+#include "gmxpre.h"
+
+#include "loggerbuilder.h"
+
+#include <memory>
+#include <vector>
+
+#include "gromacs/utility/filestream.h"
+#include "gromacs/utility/logger.h"
+#include "gromacs/utility/stringutil.h"
+#include "gromacs/utility/textwriter.h"
+
+namespace gmx
+{
+
+class LogTargetCollection : public ILogTarget
+{
+    public:
+        void addTarget(ILogTarget *target)
+        {
+            targets_.push_back(target);
+        }
+
+        virtual void writeEntry(const LogEntry &entry)
+        {
+            for (ILogTarget *target : targets_)
+            {
+                target->writeEntry(entry);
+            }
+        }
+
+    private:
+        std::vector<ILogTarget *> targets_;
+};
+
+class LogTargetFormatter : public ILogTarget
+{
+    public:
+        explicit LogTargetFormatter(TextOutputStream *stream) : writer_(stream) {}
+
+        virtual void writeEntry(const LogEntry &entry);
+
+    private:
+        TextWriter writer_;
+};
+
+
+void LogTargetFormatter::writeEntry(const LogEntry &entry)
+{
+    if (entry.asParagraph)
+    {
+        writer_.ensureEmptyLine();
+    }
+    writer_.writeLine(entry.text);
+    if (entry.asParagraph)
+    {
+        writer_.ensureEmptyLine();
+    }
+}
+
+/********************************************************************
+ * LoggerOwner::Impl
+ */
+
+class LoggerOwner::Impl
+{
+    public:
+        explicit Impl(ILogTarget *loggerTargets[MDLogger::LogLevelCount])
+            : logger_(loggerTargets)
+        {
+        }
+
+        MDLogger                                        logger_;
+        std::vector<std::unique_ptr<TextOutputStream> > streams_;
+        std::vector<std::unique_ptr<ILogTarget> >       targets_;
+};
+
+/********************************************************************
+ * LoggerOwner
+ */
+
+LoggerOwner::LoggerOwner(std::unique_ptr<Impl> impl)
+    : impl_(impl.release()), logger_(&impl_->logger_)
+{
+}
+
+LoggerOwner::LoggerOwner(LoggerOwner &&other)
+    : impl_(std::move(other.impl_)), logger_(&impl_->logger_)
+{
+}
+
+LoggerOwner &LoggerOwner::operator=(LoggerOwner &&other)
+{
+    impl_   = std::move(other.impl_);
+    logger_ = &impl_->logger_;
+    return *this;
+}
+
+LoggerOwner::~LoggerOwner()
+{
+}
+
+/********************************************************************
+ * LoggerBuilder::Impl
+ */
+
+class LoggerBuilder::Impl
+{
+    public:
+        std::vector<std::unique_ptr<TextOutputStream> > streams_;
+        std::vector<std::unique_ptr<ILogTarget> >       targets_;
+        std::vector<ILogTarget *> loggerTargets_[MDLogger::LogLevelCount];
+};
+
+/********************************************************************
+ * LoggerBuilder
+ */
+
+LoggerBuilder::LoggerBuilder()
+    : impl_(new Impl)
+{
+}
+
+LoggerBuilder::~LoggerBuilder()
+{
+}
+
+void LoggerBuilder::addTargetStream(MDLogger::LogLevel level, TextOutputStream *stream)
+{
+    impl_->targets_.push_back(std::unique_ptr<ILogTarget>(new LogTargetFormatter(stream)));
+    ILogTarget *target = impl_->targets_.back().get();
+    for (int i = 0; i <= static_cast<int>(level); ++i)
+    {
+        impl_->loggerTargets_[i].push_back(target);
+    }
+}
+
+void LoggerBuilder::addTargetFile(MDLogger::LogLevel level, FILE *fp)
+{
+    std::unique_ptr<TextOutputStream> stream(new TextOutputFile(fp));
+    addTargetStream(level, stream.get());
+    impl_->streams_.push_back(std::move(stream));
+}
+
+LoggerOwner LoggerBuilder::build()
+{
+    ILogTarget *loggerTargets[MDLogger::LogLevelCount];
+    for (int i = 0; i < MDLogger::LogLevelCount; ++i)
+    {
+        auto &levelTargets = impl_->loggerTargets_[i];
+        loggerTargets[i] = nullptr;
+        if (!levelTargets.empty())
+        {
+            if (levelTargets.size() == 1)
+            {
+                loggerTargets[i] = levelTargets[0];
+            }
+            else
+            {
+                std::unique_ptr<LogTargetCollection> collection(new LogTargetCollection);
+                for (auto &target : levelTargets)
+                {
+                    collection->addTarget(target);
+                }
+                loggerTargets[i] = collection.get();
+                impl_->targets_.push_back(std::move(collection));
+            }
+        }
+        levelTargets.clear();
+    }
+    std::unique_ptr<LoggerOwner::Impl> data(new LoggerOwner::Impl(loggerTargets));
+    data->targets_ = std::move(impl_->targets_);
+    data->streams_ = std::move(impl_->streams_);
+    return LoggerOwner(std::move(data));
+}
+
+} // namespace gmx
diff --git a/src/gromacs/utility/loggerbuilder.h b/src/gromacs/utility/loggerbuilder.h
new file mode 100644 (file)
index 0000000..75ff25f
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares functionality for initializing logging.
+ *
+ * See \ref page_logging for an overview of the functionality.
+ *
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+#ifndef GMX_UTILITY_LOGGERBUILDER_H
+#define GMX_UTILITY_LOGGERBUILDER_H
+
+#include <memory>
+#include <string>
+
+#include "gromacs/utility/classhelpers.h"
+#include "gromacs/utility/logger.h"
+
+namespace gmx
+{
+
+class TextOutputStream;
+
+class LoggerFormatterBuilder;
+class LoggerOwner;
+
+/*! \libinternal \brief
+ * Initializes loggers.
+ *
+ * This class provides methods for specifying logging targets for a logger and
+ * building the logger after all targets have been specified.  Having this
+ * separate from the logger allows using different internal data structures
+ * during initialization and operation, and simplifies the responsibilities of
+ * the involved classes.
+ *
+ * \ingroup module_utility
+ */
+class LoggerBuilder
+{
+    public:
+        LoggerBuilder();
+        ~LoggerBuilder();
+
+        /*! \brief
+         * Adds a stream to which log output is written.
+         *
+         * All output at level \p level or above it is written to \p stream.
+         * The caller is responsible of closing and freeing \p stream once the
+         * logger is discarded.
+         */
+        void addTargetStream(MDLogger::LogLevel level, TextOutputStream *stream);
+        /*! \brief
+         * Adds a file to which log output is written.
+         *
+         * All output at level \p level or above it is written to \p fp.
+         * The caller is responsible of closing \p fp once the logger is
+         * discarded.
+         */
+        void addTargetFile(MDLogger::LogLevel level, FILE *fp);
+
+        /*! \brief
+         * Builds the logger with the targets set for this builder.
+         *
+         * After this function has been called, the builder can (and should) be
+         * discarded.
+         */
+        LoggerOwner build();
+
+    private:
+        class Impl;
+
+        PrivateImplPointer<Impl> impl_;
+};
+
+/*! \libinternal \brief
+ * Manages memory for a logger built with LoggerBuilder.
+ *
+ * This class is responsible of managing all memory allocated by LoggerBuilder
+ * that is needed for operation of the actual logger.  Also the actual logger
+ * instance is owned by this class.  This allows keeing the actual logger simple
+ * and streamlined.
+ *
+ * This class supports move construction and assignment, which allows
+ * initializing it on the stack and assigning a new instance if the targets
+ * need to be changed.
+ *
+ * \ingroup module_utility
+ */
+class LoggerOwner
+{
+    public:
+        //! Move-constructs the owner.
+        LoggerOwner(LoggerOwner &&other);
+        ~LoggerOwner();
+
+        //! Move-assings the owner.
+        LoggerOwner &operator=(LoggerOwner &&other);
+
+        //! Returns the logger for writing the logs.
+        const MDLogger &logger() const { return *logger_; }
+
+    private:
+        class Impl;
+
+        LoggerOwner(std::unique_ptr<Impl> impl);
+
+        PrivateImplPointer<Impl>  impl_;
+        const MDLogger           *logger_;
+
+        friend class LoggerBuilder;
+};
+
+} // namespace gmx
+
+#endif
index 937bb541cb99510b665d0426b72a066b5ff73321..97d2853ec499829435a13cff94ad949b2def908d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2011,2012,2014, by the GROMACS development team, led by
+ * Copyright (c) 2011,2012,2014,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -71,7 +71,7 @@ MessageStringCollector::~MessageStringCollector()
 
 void MessageStringCollector::startContext(const char *name)
 {
-    impl_->contexts_.push_back(name);
+    impl_->contexts_.emplace_back(name);
 }
 
 void MessageStringCollector::append(const std::string &message)
index f472f2d15b599e25f86fcb67760e0ebe83307b0a..8e6040fd54e15680cfb380fad2621ac470f971c1 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -366,6 +366,16 @@ void please_cite(FILE *fp, const char *key)
           "GROMACS: High performance molecular simulations through multi-level parallelism from laptops to supercomputers",
           "SoftwareX",
           1, 2015, "19-25" },
+        { "Ballenegger2009",
+          "V. Ballenegger, A. Arnold, J. J. Cerdà",
+          "Simulations of non-neutral slab systems with long-range electrostatic interactions in two-dimensional periodic boundary conditions",
+          "J. Chem. Phys",
+          131, 2009, "094107" },
+        { "Hub2014a",
+          "J. S. Hub, B. L. de Groot, H. Grubmueller, G. Groenhof",
+          "Quantifying Artifacts in Ewald Simulations of Inhomogeneous Systems with a Net Charge",
+          "J. Chem. Theory Comput.",
+          10, 2014, "381-393" },
     };
 #define NSTR (int)asize(citedb)
 
diff --git a/src/gromacs/utility/strconvert.cpp b/src/gromacs/utility/strconvert.cpp
new file mode 100644 (file)
index 0000000..f85fcd3
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Implements functions in strconvert.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_utility
+ */
+#include "gmxpre.h"
+
+#include "strconvert.h"
+
+#include <cerrno>
+#include <cstdlib>
+
+#include <limits>
+#include <string>
+
+#include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/exceptions.h"
+
+namespace gmx
+{
+
+//! \cond libapi
+
+bool boolFromString(const char *value)
+{
+    if (gmx_strcasecmp(value, "1") == 0
+        || gmx_strcasecmp(value, "yes") == 0
+        || gmx_strcasecmp(value, "true") == 0)
+    {
+        return true;
+    }
+    if (gmx_strcasecmp(value, "0") == 0
+        || gmx_strcasecmp(value, "no") == 0
+        || gmx_strcasecmp(value, "false") == 0)
+    {
+        return false;
+    }
+    GMX_THROW(InvalidInputError("Invalid value: '" + std::string(value) + "'; supported values are: 1, 0, yes, no, true, false"));
+}
+
+int intFromString(const char *str)
+{
+    errno = 0;
+    char           *endptr;
+    const long int  value = std::strtol(str, &endptr, 10);
+    if (errno == ERANGE
+        || value < std::numeric_limits<int>::min()
+        || value > std::numeric_limits<int>::max())
+    {
+        GMX_THROW(InvalidInputError("Invalid value: '" + std::string(str)
+                                    + "'; it causes an integer overflow"));
+    }
+    if (str[0] == '\0' || *endptr != '\0')
+    {
+        GMX_THROW(InvalidInputError("Invalid value: '" + std::string(str)
+                                    + "'; expected an integer"));
+    }
+    return value;
+}
+
+gmx_int64_t int64FromString(const char *str)
+{
+    errno = 0;
+    char              *endptr;
+    const gmx_int64_t  value = str_to_int64_t(str, &endptr);
+    if (errno == ERANGE)
+    {
+        GMX_THROW(InvalidInputError("Invalid value: '" + std::string(str)
+                                    + "'; it causes an integer overflow"));
+    }
+    if (str[0] == '\0' || *endptr != '\0')
+    {
+        GMX_THROW(InvalidInputError("Invalid value: '" + std::string(str)
+                                    + "'; expected an integer"));
+    }
+    return value;
+}
+
+float floatFromString(const char *str)
+{
+    errno = 0;
+    char         *endptr;
+    const double  value = std::strtod(str, &endptr);
+    if (errno == ERANGE
+        || value < -std::numeric_limits<float>::max()
+        || value >  std::numeric_limits<float>::max())
+    {
+        GMX_THROW(InvalidInputError("Invalid value: '" + std::string(str)
+                                    + "'; it causes an overflow/underflow"));
+    }
+    if (str[0] == '\0' || *endptr != '\0')
+    {
+        GMX_THROW(InvalidInputError("Invalid value: '" + std::string(str)
+                                    + "'; expected a number"));
+    }
+    return value;
+}
+
+double doubleFromString(const char *str)
+{
+    errno = 0;
+    char         *endptr;
+    const double  value = std::strtod(str, &endptr);
+    if (errno == ERANGE)
+    {
+        GMX_THROW(InvalidInputError("Invalid value: '" + std::string(str)
+                                    + "'; it causes an overflow/underflow"));
+    }
+    if (str[0] == '\0' || *endptr != '\0')
+    {
+        GMX_THROW(InvalidInputError("Invalid value: '" + std::string(str)
+                                    + "'; expected a number"));
+    }
+    return value;
+}
+
+//! \endcond
+
+} // namespace gmx
diff --git a/src/gromacs/utility/strconvert.h b/src/gromacs/utility/strconvert.h
new file mode 100644 (file)
index 0000000..8275e32
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares common utility functions for conversions from strings.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+#ifndef GMX_UTILITY_STRCONVERT_H
+#define GMX_UTILITY_STRCONVERT_H
+
+#include <string>
+
+#include "gromacs/utility/basedefinitions.h"
+
+namespace gmx
+{
+
+//! \cond libapi
+//! \addtogroup module_utility
+//! \{
+
+/*! \brief
+ * Parses a boolean from a string.
+ *
+ * \throws  InvalidInputError if `str` is not recognized as a boolean value.
+ */
+bool boolFromString(const char *str);
+/*! \brief
+ * Parses an integer from a string.
+ *
+ * \throws  InvalidInputError if `str` is not a valid integer.
+ *
+ * Also checks for overflow.
+ */
+int intFromString(const char *str);
+/*! \brief
+ * Parses a 64-bit integer from a string.
+ *
+ * \throws  InvalidInputError if `str` is not a valid integer.
+ *
+ * Also checks for overflow.
+ */
+gmx_int64_t int64FromString(const char *str);
+/*! \brief
+ * Parses a float value from a string.
+ *
+ * \throws  InvalidInputError if `str` is not a valid number.
+ *
+ * Also checks for overflow.
+ */
+float floatFromString(const char *str);
+/*! \brief
+ * Parses a double value from a string.
+ *
+ * \throws  InvalidInputError if `str` is not a valid number.
+ *
+ * Also checks for overflow.
+ */
+double doubleFromString(const char *str);
+
+/*! \brief
+ * Parses a value from a string to a given type.
+ *
+ * \tparam T Type of value to parse.
+ *
+ * `T` can only be one of the types that is explicity supported.
+ * The main use for this function is to write `fromString<real>(value)`,
+ * but it can also be used for other types for consistency.
+ */
+template <typename T> static inline T fromString(const char *str);
+//! \copydoc fromString(const char *)
+template <typename T> static inline T fromString(const std::string &str)
+{
+    return fromString<T>(str.c_str());
+}
+/*! \copydoc fromString(const char *)
+ *
+ * Provided for situations where overload resolution cannot easily resolve the
+ * desired std::string parameter.
+ */
+template <typename T> static inline T fromStdString(const std::string &str)
+{
+    return fromString<T>(str.c_str());
+}
+
+//! Implementation for boolean values.
+template <> inline
+bool fromString<bool>(const char *str) { return boolFromString(str); }
+//! Implementation for integer values.
+template <> inline
+int fromString<int>(const char *str) { return intFromString(str); }
+//! Implementation for 64-bit integer values.
+template <> inline
+gmx_int64_t fromString<gmx_int64_t>(const char *str) { return int64FromString(str); }
+//! Implementation for float values.
+template <> inline
+float fromString<float>(const char *str) { return floatFromString(str); }
+//! Implementation for double values.
+template <> inline
+double fromString<double>(const char *str) { return doubleFromString(str); }
+
+//! \}
+//! \endcond
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/utility/stringcompare.h b/src/gromacs/utility/stringcompare.h
new file mode 100644 (file)
index 0000000..211a4b6
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares utility functionst for string comparison.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+#ifndef GMX_UTILITY_STRINGCOMPARE_H
+#define GMX_UTILITY_STRINGCOMPARE_H
+
+#include <string>
+
+#include "gromacs/utility/cstringutil.h"
+
+namespace gmx
+{
+
+//! \cond libapi
+/*! \brief
+ * Specifies how strings should be compared in various contexts.
+ *
+ * \ingroup module_utility
+ */
+enum class StringCompareType
+{
+    //! Only exact matches are accepted.
+    Exact,
+    //! Case-insensitive comparison.
+    CaseInsensitive,
+    //! Case-insensitive comparison that also ignores '-' and '_'.
+    CaseAndDashInsensitive
+};
+//! \endcond
+
+/*! \libinternal \brief
+ * Compare object for std::string STL containers and algorithms that supports
+ * run-time decision on how to compare.
+ *
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+class StringCompare
+{
+    public:
+        /*! \brief
+         * Creates a comparer with the given type
+         *
+         * This is not explicit, which allows passing \ref StringCompareType
+         * directly to, e.g., `std::map` constructors.
+         */
+        StringCompare(StringCompareType type = StringCompareType::Exact)
+            : type_(type) {}
+
+        //! The comparison operation.
+        bool operator()(const std::string &a, const std::string &b) const
+        {
+            switch (type_)
+            {
+                case StringCompareType::Exact:
+                    return a < b;
+                case StringCompareType::CaseInsensitive:
+                    return gmx_strcasecmp(a.c_str(), b.c_str()) < 0;
+                case StringCompareType::CaseAndDashInsensitive:
+                    return gmx_strcasecmp_min(a.c_str(), b.c_str()) < 0;
+            }
+            return a < b;
+        }
+
+    private:
+        StringCompareType type_;
+};
+
+} // namespace gmx
+
+#endif
index cc3b1bfa3b9928779c80ce1dd4f21360730453ee..1a1b1c1e224e4ef6e64da0e16aac0e13693e32dd 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -133,7 +133,16 @@ std::string stripString(const std::string &str)
 
 std::string formatString(const char *fmt, ...)
 {
-    va_list           ap;
+    va_list     ap;
+    va_start(ap, fmt);
+    std::string result = formatStringV(fmt, ap);
+    va_end(ap);
+    return result;
+}
+
+std::string formatStringV(const char *fmt, va_list ap)
+{
+    va_list           ap_copy;
     char              staticBuf[1024];
     int               length = 1024;
     std::vector<char> dynamicBuf;
@@ -143,9 +152,9 @@ std::string formatString(const char *fmt, ...)
     // provides their own way of doing things...
     while (1)
     {
-        va_start(ap, fmt);
-        int n = vsnprintf(buf, length, fmt, ap);
-        va_end(ap);
+        va_copy(ap_copy, ap);
+        int n = vsnprintf(buf, length, fmt, ap_copy);
+        va_end(ap_copy);
         if (n > -1 && n < length)
         {
             std::string result(buf);
@@ -182,8 +191,27 @@ std::vector<std::string> splitString(const std::string &str)
         }
         if (startPos != end)
         {
-            result.push_back(std::string(startPos, currPos));
+            result.emplace_back(startPos, currPos);
+        }
+    }
+    return result;
+}
+
+std::vector<std::string> splitDelimitedString(const std::string &str, char delim)
+{
+    std::vector<std::string> result;
+    size_t                   currPos = 0;
+    const size_t             len     = str.length();
+    if (len > 0)
+    {
+        size_t nextDelim;
+        do
+        {
+            nextDelim = str.find(delim, currPos);
+            result.push_back(str.substr(currPos, nextDelim - currPos));
+            currPos = nextDelim < len ? nextDelim + 1 : len;
         }
+        while (currPos < len || nextDelim < len);
     }
     return result;
 }
index f54aedaa9ebf0b700b632e40e2c7f7ef04414bd2..592d517c7332731c16eff2e046b5d2252fbe1bb9 100644 (file)
@@ -43,6 +43,7 @@
 #ifndef GMX_UTILITY_STRINGUTIL_H
 #define GMX_UTILITY_STRINGUTIL_H
 
+#include <cstdarg>
 #include <cstring>
 
 #include <string>
@@ -178,6 +179,16 @@ std::string stripString(const std::string &str);
  * supported.
  */
 std::string formatString(const char *fmt, ...);
+/*! \brief
+ * Formats a string (vsnprintf() wrapper).
+ *
+ * \throws  std::bad_alloc if out of memory.
+ *
+ * This function works like vsprintf(), except that it returns an std::string
+ * instead of requiring a preallocated buffer.  Arbitrary length output is
+ * supported.
+ */
+std::string formatStringV(const char *fmt, va_list ap);
 
 /*! \brief Function object that wraps a call to formatString() that
  * expects a single conversion argument, for use with algorithms. */
@@ -332,6 +343,19 @@ static inline const char *boolToString(bool value)
  * separator.
  */
 std::vector<std::string> splitString(const std::string &str);
+/*! \brief
+ * Splits a string to tokens separated by a given delimiter.
+ *
+ * \param[in] str   String to process.
+ * \param[in] delim Delimiter to use for splitting.
+ * \returns   \p str split into tokens at delimiter.
+ * \throws    std::bad_alloc if out of memory.
+ *
+ * Unlike splitString(), consencutive delimiters will generate empty tokens, as
+ * will leading or trailing delimiters.
+ * Empty input will return an empty vector.
+ */
+std::vector<std::string> splitDelimitedString(const std::string &str, char delim);
 
 /*! \brief
  * Replace all occurrences of a string with another string.
index 3fe52c713c5b9ec7cccf3a7a04d844df358b757c..711955f78a8e04f8199d348f438cc40b1730d9a2 100644 (file)
@@ -37,6 +37,9 @@ gmx_add_unit_test(UtilityUnitTests utility-test
                   arrayref.cpp
                   basedefinitions.cpp
                   bitmask32.cpp bitmask64.cpp bitmask128.cpp
+                  keyvaluetreeserializer.cpp
+                  keyvaluetreetransform.cpp
+                  logger.cpp
                   path.cpp
                   stringutil.cpp
                   textwriter.cpp
index d7868e2d05dbe0ead9b104609d3aeb816344a8fa..1face9567dcf0b300c4875a7155f8250d3b501e9 100644 (file)
@@ -42,8 +42,6 @@
 
 #include "gromacs/utility/arrayref.h"
 
-#include "config.h"
-
 #include <vector>
 
 #include <gtest/gtest.h>
@@ -217,16 +215,10 @@ struct Helper
  *
  * There, we take a non-const struct-field array of static length and
  * make an ArrayRef to it using the template constructor that is
- * supposed to infer the length from the static size. But on xlc on
- * BlueGene/Q, if the base type is not char (or unsigned char), the
- * generated code ends up with an ArrayRef of zero size, so everything
- * breaks. Presumably the default code path accidentally works for
- * char.
- *
- * Fortunately, all current uses of that constructor have a base type
- * of char, so there's no big problem. Using a pointer-based
- * constructor does work, if there's ever a problem (and that is
- * tested above). */
+ * supposed to infer the length from the static size. This has
+ * been a problem (for a compiler that we no longer support),
+ * so we test it.
+ */
 
 TYPED_TEST(ArrayRefTest, ConstructFromStructFieldWithTemplateConstructorWorks)
 {
@@ -238,12 +230,7 @@ TYPED_TEST(ArrayRefTest, ConstructFromStructFieldWithTemplateConstructorWorks)
         h.a[i] = a[i];
     }
     typename TestFixture::ArrayRefType arrayRef(h.a);
-#if GMX_TARGET_BGQ && defined(__xlC__)
-    if (sizeof(typename TestFixture::ValueType) == sizeof(char))
-#endif
-    {
-        this->runTests(h.a, h.size, h.a, arrayRef);
-    }
+    this->runTests(h.a, h.size, h.a, arrayRef);
 }
 
 #else   // GTEST_HAS_TYPED_TEST
diff --git a/src/gromacs/utility/tests/keyvaluetreeserializer.cpp b/src/gromacs/utility/tests/keyvaluetreeserializer.cpp
new file mode 100644 (file)
index 0000000..0015614
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+#include "gmxpre.h"
+
+#include "gromacs/utility/keyvaluetreeserializer.h"
+
+#include <gtest/gtest.h>
+
+#include "gromacs/utility/iserializer.h"
+#include "gromacs/utility/keyvaluetreebuilder.h"
+
+#include "testutils/refdata.h"
+
+namespace
+{
+
+class RefDataWriteSerializer : public gmx::ISerializer
+{
+    public:
+        RefDataWriteSerializer(gmx::test::TestReferenceChecker *parentChecker,
+                               const char                      *id)
+            : checker_(parentChecker->checkCompound("SerializedData", id))
+        {
+        }
+
+        virtual bool reading() const { return false; }
+
+        virtual void doUChar(unsigned char *value)
+        {
+            checker_.checkUChar(*value, nullptr);
+        }
+        virtual void doInt(int *value)
+        {
+            checker_.checkInteger(*value, nullptr);
+        }
+        virtual void doFloat(float *value)
+        {
+            checker_.checkFloat(*value, nullptr);
+        }
+        virtual void doDouble(double *value)
+        {
+            checker_.checkDouble(*value, nullptr);
+        }
+        virtual void doString(std::string *value)
+        {
+            checker_.checkString(*value, nullptr);
+        }
+
+    private:
+        gmx::test::TestReferenceChecker checker_;
+};
+
+class RefDataReadSerializer : public gmx::ISerializer
+{
+    public:
+        RefDataReadSerializer(gmx::test::TestReferenceChecker *parentChecker,
+                              const char                      *id)
+            : checker_(parentChecker->checkCompound("SerializedData", id))
+        {
+        }
+
+        virtual bool reading() const { return true; }
+
+        virtual void doUChar(unsigned char *value)
+        {
+            *value = checker_.readUChar(nullptr);
+        }
+        virtual void doInt(int *value)
+        {
+            *value = checker_.readInteger(nullptr);
+        }
+        virtual void doFloat(float *value)
+        {
+            *value = checker_.readFloat(nullptr);
+        }
+        virtual void doDouble(double *value)
+        {
+            *value = checker_.readDouble(nullptr);
+        }
+        virtual void doString(std::string *value)
+        {
+            *value = checker_.readString(nullptr);
+        }
+
+    private:
+        gmx::test::TestReferenceChecker checker_;
+};
+
+class KeyValueTreeSerializerTest : public ::testing::Test
+{
+    public:
+        void runTest()
+        {
+            gmx::KeyValueTreeObject           input(builder_.build());
+            gmx::test::TestReferenceData      data;
+            gmx::test::TestReferenceChecker   checker(data.rootChecker());
+            checker.checkKeyValueTreeObject(input, "Input");
+            {
+                RefDataWriteSerializer        serializer(&checker, "Stream");
+                gmx::serializeKeyValueTree(input, &serializer);
+            }
+            {
+                RefDataReadSerializer         serializer(&checker, "Stream");
+                gmx::KeyValueTreeObject       output
+                    = gmx::deserializeKeyValueTree(&serializer);
+                checker.checkKeyValueTreeObject(output, "Input");
+            }
+        }
+
+        gmx::KeyValueTreeBuilder builder_;
+};
+
+TEST_F(KeyValueTreeSerializerTest, EmptyTree)
+{
+    runTest();
+}
+
+TEST_F(KeyValueTreeSerializerTest, SimpleObject)
+{
+    builder_.rootObject().addValue<int>("foo", 1);
+    builder_.rootObject().addValue<std::string>("bar", "a");
+    builder_.rootObject().addValue<float>("f", 1.5);
+    builder_.rootObject().addValue<double>("d", 2.5);
+    runTest();
+}
+
+TEST_F(KeyValueTreeSerializerTest, ObjectWithArrays)
+{
+    auto arr1 = builder_.rootObject().addUniformArray<int>("a");
+    arr1.addValue(1);
+    arr1.addValue(2);
+    auto arr2 = builder_.rootObject().addUniformArray<std::string>("b");
+    arr2.addValue("foo");
+    arr2.addValue("bar");
+    runTest();
+}
+
+TEST_F(KeyValueTreeSerializerTest, ObjectWithObjects)
+{
+    auto obj1 = builder_.rootObject().addObject("obj");
+    obj1.addValue<int>("a", 1);
+    obj1.addValue<std::string>("b", "foo");
+    auto obj2 = builder_.rootObject().addObject("obj2");
+    obj2.addValue<int>("c", 2);
+    obj2.addValue<std::string>("d", "bar");
+    builder_.rootObject().addValue<int>("foo", 3);
+    runTest();
+}
+
+} // namespace
diff --git a/src/gromacs/utility/tests/keyvaluetreetransform.cpp b/src/gromacs/utility/tests/keyvaluetreetransform.cpp
new file mode 100644 (file)
index 0000000..64ba316
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+#include "gmxpre.h"
+
+#include "gromacs/utility/keyvaluetreetransform.h"
+
+#include <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/keyvaluetree.h"
+#include "gromacs/utility/keyvaluetreebuilder.h"
+#include "gromacs/utility/strconvert.h"
+#include "gromacs/utility/stringcompare.h"
+#include "gromacs/utility/stringutil.h"
+
+#include "testutils/refdata.h"
+#include "testutils/testasserts.h"
+
+namespace
+{
+
+class TreeValueTransformTest : public ::testing::Test
+{
+    public:
+        void testTransform(const gmx::KeyValueTreeObject      &input,
+                           const gmx::KeyValueTreeTransformer &transform)
+        {
+            gmx::KeyValueTreeTransformResult  result = transform.transform(input, nullptr);
+            gmx::KeyValueTreeObject           object = result.object();
+
+            gmx::test::TestReferenceData      data;
+            gmx::test::TestReferenceChecker   checker(data.rootChecker());
+            checker.checkKeyValueTreeObject(input, "Input");
+            auto mappedPaths = transform.mappedPaths();
+            checker.checkSequence(mappedPaths.begin(), mappedPaths.end(), "MappedPaths",
+                                  &TreeValueTransformTest::checkMappedPath);
+            checker.checkKeyValueTreeObject(object, "Tree");
+            checkBackMapping(&checker, object, result.backMapping());
+        }
+
+    private:
+        static void checkMappedPath(gmx::test::TestReferenceChecker *checker,
+                                    const gmx::KeyValueTreePath     &path)
+        {
+            checker->checkString(path.toString(), nullptr);
+        }
+        void checkBackMapping(gmx::test::TestReferenceChecker     *checker,
+                              const gmx::KeyValueTreeObject       &object,
+                              const gmx::IKeyValueTreeBackMapping &mapping)
+        {
+            auto compound(checker->checkCompound("BackMapping", "Mapping"));
+            checkBackMappingImpl(&compound, object, mapping, gmx::KeyValueTreePath());
+        }
+
+        void checkBackMappingImpl(gmx::test::TestReferenceChecker     *checker,
+                                  const gmx::KeyValueTreeObject       &object,
+                                  const gmx::IKeyValueTreeBackMapping &mapping,
+                                  const gmx::KeyValueTreePath         &prefix)
+        {
+            for (const auto &prop : object.properties())
+            {
+                gmx::KeyValueTreePath path = prefix;
+                path.append(prop.key());
+                if (prop.value().isObject())
+                {
+                    checkBackMappingImpl(checker, prop.value().asObject(), mapping, path);
+                }
+                else
+                {
+                    gmx::KeyValueTreePath orgPath = mapping.originalPath(path);
+                    checker->checkString(orgPath.toString(), path.toString().c_str());
+                }
+            }
+        }
+};
+
+TEST_F(TreeValueTransformTest, SimpleTransforms)
+{
+    gmx::KeyValueTreeBuilder     builder;
+    builder.rootObject().addValue<std::string>("a", "1");
+    builder.rootObject().addValue<std::string>("b", "2");
+    gmx::KeyValueTreeObject      input = builder.build();
+
+    gmx::KeyValueTreeTransformer transform;
+    transform.rules()->addRule()
+        .from<std::string>("/a").to<int>("/i").transformWith(&gmx::fromStdString<int>);
+    transform.rules()->addRule()
+        .from<std::string>("/b").to<int>("/j").transformWith(&gmx::fromStdString<int>);
+
+    testTransform(input, transform);
+}
+
+TEST_F(TreeValueTransformTest, SimpleTransformsCaseAndDashInsensitive)
+{
+    gmx::KeyValueTreeBuilder     builder;
+    builder.rootObject().addValue<std::string>("a-x", "1");
+    builder.rootObject().addValue<std::string>("by", "2");
+    gmx::KeyValueTreeObject      input = builder.build();
+
+    gmx::KeyValueTreeTransformer transform;
+    transform.rules()->addRule()
+        .keyMatchType("/", gmx::StringCompareType::CaseAndDashInsensitive);
+    transform.rules()->addRule()
+        .from<std::string>("/Ax").to<int>("/i").transformWith(&gmx::fromStdString<int>);
+    transform.rules()->addRule()
+        .from<std::string>("/B-Y").to<int>("/j").transformWith(&gmx::fromStdString<int>);
+
+    testTransform(input, transform);
+}
+
+TEST_F(TreeValueTransformTest, SimpleTransformsToObject)
+{
+    gmx::KeyValueTreeBuilder     builder;
+    builder.rootObject().addValue<std::string>("a", "1");
+    builder.rootObject().addValue<std::string>("b", "2");
+    gmx::KeyValueTreeObject      input = builder.build();
+
+    gmx::KeyValueTreeTransformer transform;
+    transform.rules()->addRule()
+        .from<std::string>("/a").to<int>("/foo/i").transformWith(&gmx::fromStdString<int>);
+    transform.rules()->addRule()
+        .from<std::string>("/b").to<int>("/foo/j").transformWith(&gmx::fromStdString<int>);
+
+    testTransform(input, transform);
+}
+
+
+TEST_F(TreeValueTransformTest, ObjectFromString)
+{
+    gmx::KeyValueTreeBuilder     builder;
+    builder.rootObject().addValue<std::string>("a", "1 2");
+    gmx::KeyValueTreeObject      input = builder.build();
+
+    gmx::KeyValueTreeTransformer transform;
+    transform.rules()->addRule()
+        .from<std::string>("/a").toObject("/foo").transformWith(
+            [] (gmx::KeyValueTreeObjectBuilder *builder, const std::string &value)
+            {
+                std::vector<std::string> values = gmx::splitString(value);
+                builder->addValue<int>("a", gmx::fromString<int>(values[0]));
+                builder->addValue<int>("b", gmx::fromString<int>(values[1]));
+            });
+
+    testTransform(input, transform);
+}
+
+TEST_F(TreeValueTransformTest, ObjectFromMultipleStrings)
+{
+    gmx::KeyValueTreeBuilder     builder;
+    builder.rootObject().addValue<std::string>("a", "1");
+    builder.rootObject().addValue<std::string>("b", "2 3");
+    gmx::KeyValueTreeObject      input = builder.build();
+
+    gmx::KeyValueTreeTransformer transform;
+    transform.rules()->addRule()
+        .from<std::string>("/a").to<int>("/foo/a").transformWith(&gmx::fromStdString<int>);
+    transform.rules()->addRule()
+        .from<std::string>("/b").toObject("/foo").transformWith(
+            [] (gmx::KeyValueTreeObjectBuilder *builder, const std::string &value)
+            {
+                std::vector<std::string> values = gmx::splitString(value);
+                builder->addValue<int>("b", gmx::fromString<int>(values[0]));
+                builder->addValue<int>("c", gmx::fromString<int>(values[1]));
+            });
+
+    testTransform(input, transform);
+}
+
+/********************************************************************
+ * Tests for errors
+ */
+
+TEST(TreeValueTransformErrorTest, ConversionError)
+{
+    gmx::KeyValueTreeBuilder     builder;
+    builder.rootObject().addValue<std::string>("a", "foo");
+    gmx::KeyValueTreeObject      input = builder.build();
+
+    gmx::KeyValueTreeTransformer transform;
+    transform.rules()->addRule()
+        .from<std::string>("/a").to<int>("/i").transformWith(&gmx::fromStdString<int>);
+
+    EXPECT_THROW_GMX(transform.transform(input, nullptr), gmx::InvalidInputError);
+}
+
+} // namespace
diff --git a/src/gromacs/utility/tests/logger.cpp b/src/gromacs/utility/tests/logger.cpp
new file mode 100644 (file)
index 0000000..3385ab4
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+#include "gmxpre.h"
+
+#include "gromacs/utility/logger.h"
+
+#include <gtest/gtest.h>
+
+#include "gromacs/utility/loggerbuilder.h"
+#include "gromacs/utility/stringstream.h"
+
+#include "testutils/stringtest.h"
+#include "testutils/testfilemanager.h"
+
+namespace
+{
+
+//! Test fixture for logging tests.
+typedef gmx::test::StringTestBase LoggerTest;
+
+TEST_F(LoggerTest, EmptyLoggerWorks)
+{
+    gmx::MDLogger logger;
+    GMX_LOG(logger.info).appendText("foobar");
+    GMX_LOG(logger.warning).appendText("foobar").asParagraph();
+}
+
+TEST_F(LoggerTest, LogsToStream)
+{
+    gmx::StringOutputStream stream;
+    gmx::LoggerBuilder      builder;
+    builder.addTargetStream(gmx::MDLogger::LogLevel::Info, &stream);
+    gmx::LoggerOwner        owner  = builder.build();
+    const gmx::MDLogger    &logger = owner.logger();
+    GMX_LOG(logger.info).appendText("line");
+    GMX_LOG(logger.warning).appendText("par").asParagraph();
+    GMX_LOG(logger.info).appendText("line2");
+    checkText(stream.toString(), "Output");
+}
+
+TEST_F(LoggerTest, LogsToFile)
+{
+    gmx::test::TestFileManager files;
+    std::string                filename(files.getTemporaryFilePath("log.txt"));
+    FILE                      *fp = fopen(filename.c_str(), "w");
+    {
+        gmx::LoggerBuilder      builder;
+        builder.addTargetFile(gmx::MDLogger::LogLevel::Info, fp);
+        gmx::LoggerOwner        owner  = builder.build();
+        const gmx::MDLogger    &logger = owner.logger();
+        GMX_LOG(logger.info).appendText("line");
+        GMX_LOG(logger.warning).appendText("par").asParagraph();
+        GMX_LOG(logger.info).appendText("line2");
+    }
+    fclose(fp);
+    checkFileContents(filename, "Output");
+}
+
+TEST_F(LoggerTest, LevelFilteringWorks)
+{
+    gmx::StringOutputStream stream;
+    gmx::LoggerBuilder      builder;
+    builder.addTargetStream(gmx::MDLogger::LogLevel::Warning, &stream);
+    gmx::LoggerOwner        owner  = builder.build();
+    const gmx::MDLogger    &logger = owner.logger();
+    GMX_LOG(logger.info).appendText("line");
+    GMX_LOG(logger.warning).appendText("par").asParagraph();
+    GMX_LOG(logger.info).appendText("line2");
+    checkText(stream.toString(), "Output");
+}
+
+TEST_F(LoggerTest, LogsToMultipleStreams)
+{
+    gmx::StringOutputStream stream1;
+    gmx::StringOutputStream stream2;
+    gmx::LoggerBuilder      builder;
+    builder.addTargetStream(gmx::MDLogger::LogLevel::Info, &stream1);
+    builder.addTargetStream(gmx::MDLogger::LogLevel::Warning, &stream2);
+    gmx::LoggerOwner        owner  = builder.build();
+    const gmx::MDLogger    &logger = owner.logger();
+    GMX_LOG(logger.info).appendText("line");
+    GMX_LOG(logger.warning).appendText("par").asParagraph();
+    GMX_LOG(logger.info).appendText("line2");
+    checkText(stream1.toString(), "Output1");
+    checkText(stream2.toString(), "Output2");
+}
+
+} // namespace
diff --git a/src/gromacs/utility/tests/refdata/KeyValueTreeSerializerTest_EmptyTree.xml b/src/gromacs/utility/tests/refdata/KeyValueTreeSerializerTest_EmptyTree.xml
new file mode 100644 (file)
index 0000000..0fe3670
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Object Name="Input"></Object>
+  <SerializedData Name="Stream">
+    <Int>0</Int>
+  </SerializedData>
+</ReferenceData>
diff --git a/src/gromacs/utility/tests/refdata/KeyValueTreeSerializerTest_ObjectWithArrays.xml b/src/gromacs/utility/tests/refdata/KeyValueTreeSerializerTest_ObjectWithArrays.xml
new file mode 100644 (file)
index 0000000..6e809da
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Object Name="Input">
+    <Sequence Name="a">
+      <Int Name="Length">2</Int>
+      <Int>1</Int>
+      <Int>2</Int>
+    </Sequence>
+    <Sequence Name="b">
+      <Int Name="Length">2</Int>
+      <String>foo</String>
+      <String>bar</String>
+    </Sequence>
+  </Object>
+  <SerializedData Name="Stream">
+    <Int>2</Int>
+    <String>a</String>
+    <UChar>65</UChar>
+    <Int>2</Int>
+    <UChar>105</UChar>
+    <Int>1</Int>
+    <UChar>105</UChar>
+    <Int>2</Int>
+    <String>b</String>
+    <UChar>65</UChar>
+    <Int>2</Int>
+    <UChar>115</UChar>
+    <String>foo</String>
+    <UChar>115</UChar>
+    <String>bar</String>
+  </SerializedData>
+</ReferenceData>
diff --git a/src/gromacs/utility/tests/refdata/KeyValueTreeSerializerTest_ObjectWithObjects.xml b/src/gromacs/utility/tests/refdata/KeyValueTreeSerializerTest_ObjectWithObjects.xml
new file mode 100644 (file)
index 0000000..f7eeb51
--- /dev/null
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Object Name="Input">
+    <Object Name="obj">
+      <Int Name="a">1</Int>
+      <String Name="b">foo</String>
+    </Object>
+    <Object Name="obj2">
+      <Int Name="c">2</Int>
+      <String Name="d">bar</String>
+    </Object>
+    <Int Name="foo">3</Int>
+  </Object>
+  <SerializedData Name="Stream">
+    <Int>3</Int>
+    <String>obj</String>
+    <UChar>79</UChar>
+    <Int>2</Int>
+    <String>a</String>
+    <UChar>105</UChar>
+    <Int>1</Int>
+    <String>b</String>
+    <UChar>115</UChar>
+    <String>foo</String>
+    <String>obj2</String>
+    <UChar>79</UChar>
+    <Int>2</Int>
+    <String>c</String>
+    <UChar>105</UChar>
+    <Int>2</Int>
+    <String>d</String>
+    <UChar>115</UChar>
+    <String>bar</String>
+    <String>foo</String>
+    <UChar>105</UChar>
+    <Int>3</Int>
+  </SerializedData>
+</ReferenceData>
diff --git a/src/gromacs/utility/tests/refdata/KeyValueTreeSerializerTest_SimpleObject.xml b/src/gromacs/utility/tests/refdata/KeyValueTreeSerializerTest_SimpleObject.xml
new file mode 100644 (file)
index 0000000..5e7a62f
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Object Name="Input">
+    <Int Name="foo">1</Int>
+    <String Name="bar">a</String>
+    <Real Name="f">1.5</Real>
+    <Real Name="d">2.5</Real>
+  </Object>
+  <SerializedData Name="Stream">
+    <Int>4</Int>
+    <String>foo</String>
+    <UChar>105</UChar>
+    <Int>1</Int>
+    <String>bar</String>
+    <UChar>115</UChar>
+    <String>a</String>
+    <String>f</String>
+    <UChar>102</UChar>
+    <Real>1.5</Real>
+    <String>d</String>
+    <UChar>100</UChar>
+    <Real>2.5</Real>
+  </SerializedData>
+</ReferenceData>
diff --git a/src/gromacs/utility/tests/refdata/LoggerTest_LevelFilteringWorks.xml b/src/gromacs/utility/tests/refdata/LoggerTest_LevelFilteringWorks.xml
new file mode 100644 (file)
index 0000000..fac25be
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <String Name="Output"><![CDATA[
+par
+]]></String>
+</ReferenceData>
diff --git a/src/gromacs/utility/tests/refdata/LoggerTest_LogsToFile.xml b/src/gromacs/utility/tests/refdata/LoggerTest_LogsToFile.xml
new file mode 100644 (file)
index 0000000..79dfcd4
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <String Name="Output"><![CDATA[
+line
+
+par
+
+line2
+]]></String>
+</ReferenceData>
diff --git a/src/gromacs/utility/tests/refdata/LoggerTest_LogsToMultipleStreams.xml b/src/gromacs/utility/tests/refdata/LoggerTest_LogsToMultipleStreams.xml
new file mode 100644 (file)
index 0000000..9a7bee1
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <String Name="Output1"><![CDATA[
+line
+
+par
+
+line2
+]]></String>
+  <String Name="Output2"><![CDATA[
+par
+]]></String>
+</ReferenceData>
diff --git a/src/gromacs/utility/tests/refdata/LoggerTest_LogsToStream.xml b/src/gromacs/utility/tests/refdata/LoggerTest_LogsToStream.xml
new file mode 100644 (file)
index 0000000..79dfcd4
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <String Name="Output"><![CDATA[
+line
+
+par
+
+line2
+]]></String>
+</ReferenceData>
diff --git a/src/gromacs/utility/tests/refdata/TreeValueTransformTest_ObjectFromMultipleStrings.xml b/src/gromacs/utility/tests/refdata/TreeValueTransformTest_ObjectFromMultipleStrings.xml
new file mode 100644 (file)
index 0000000..2815bdb
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Object Name="Input">
+    <String Name="a">1</String>
+    <String Name="b">2 3</String>
+  </Object>
+  <Sequence Name="MappedPaths">
+    <Int Name="Length">2</Int>
+    <String>/a</String>
+    <String>/b</String>
+  </Sequence>
+  <Object Name="Tree">
+    <Object Name="foo">
+      <Int Name="a">1</Int>
+      <Int Name="b">2</Int>
+      <Int Name="c">3</Int>
+    </Object>
+  </Object>
+  <BackMapping Name="Mapping">
+    <String Name="/foo/a">/a</String>
+    <String Name="/foo/b">/b</String>
+    <String Name="/foo/c">/b</String>
+  </BackMapping>
+</ReferenceData>
diff --git a/src/gromacs/utility/tests/refdata/TreeValueTransformTest_ObjectFromString.xml b/src/gromacs/utility/tests/refdata/TreeValueTransformTest_ObjectFromString.xml
new file mode 100644 (file)
index 0000000..0f0dac9
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Object Name="Input">
+    <String Name="a">1 2</String>
+  </Object>
+  <Sequence Name="MappedPaths">
+    <Int Name="Length">1</Int>
+    <String>/a</String>
+  </Sequence>
+  <Object Name="Tree">
+    <Object Name="foo">
+      <Int Name="a">1</Int>
+      <Int Name="b">2</Int>
+    </Object>
+  </Object>
+  <BackMapping Name="Mapping">
+    <String Name="/foo/a">/a</String>
+    <String Name="/foo/b">/a</String>
+  </BackMapping>
+</ReferenceData>
diff --git a/src/gromacs/utility/tests/refdata/TreeValueTransformTest_SimpleTransforms.xml b/src/gromacs/utility/tests/refdata/TreeValueTransformTest_SimpleTransforms.xml
new file mode 100644 (file)
index 0000000..1fecf83
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Object Name="Input">
+    <String Name="a">1</String>
+    <String Name="b">2</String>
+  </Object>
+  <Sequence Name="MappedPaths">
+    <Int Name="Length">2</Int>
+    <String>/a</String>
+    <String>/b</String>
+  </Sequence>
+  <Object Name="Tree">
+    <Int Name="i">1</Int>
+    <Int Name="j">2</Int>
+  </Object>
+  <BackMapping Name="Mapping">
+    <String Name="/i">/a</String>
+    <String Name="/j">/b</String>
+  </BackMapping>
+</ReferenceData>
diff --git a/src/gromacs/utility/tests/refdata/TreeValueTransformTest_SimpleTransformsCaseAndDashInsensitive.xml b/src/gromacs/utility/tests/refdata/TreeValueTransformTest_SimpleTransformsCaseAndDashInsensitive.xml
new file mode 100644 (file)
index 0000000..3e4ae5e
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Object Name="Input">
+    <String Name="a-x">1</String>
+    <String Name="by">2</String>
+  </Object>
+  <Sequence Name="MappedPaths">
+    <Int Name="Length">2</Int>
+    <String>/Ax</String>
+    <String>/B-Y</String>
+  </Sequence>
+  <Object Name="Tree">
+    <Int Name="i">1</Int>
+    <Int Name="j">2</Int>
+  </Object>
+  <BackMapping Name="Mapping">
+    <String Name="/i">/a-x</String>
+    <String Name="/j">/by</String>
+  </BackMapping>
+</ReferenceData>
diff --git a/src/gromacs/utility/tests/refdata/TreeValueTransformTest_SimpleTransformsToObject.xml b/src/gromacs/utility/tests/refdata/TreeValueTransformTest_SimpleTransformsToObject.xml
new file mode 100644 (file)
index 0000000..603fd2b
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Object Name="Input">
+    <String Name="a">1</String>
+    <String Name="b">2</String>
+  </Object>
+  <Sequence Name="MappedPaths">
+    <Int Name="Length">2</Int>
+    <String>/a</String>
+    <String>/b</String>
+  </Sequence>
+  <Object Name="Tree">
+    <Object Name="foo">
+      <Int Name="i">1</Int>
+      <Int Name="j">2</Int>
+    </Object>
+  </Object>
+  <BackMapping Name="Mapping">
+    <String Name="/foo/i">/a</String>
+    <String Name="/foo/j">/b</String>
+  </BackMapping>
+</ReferenceData>
index 7145fdb109a48cddf46ce992ad2fa340e5fce318..08a844d53bca90124447e143d1aa9edddb8e1ecb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2012,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -126,6 +126,18 @@ TEST(StringUtilityTest, SplitString)
     EXPECT_THAT(gmx::splitString("   "), IsEmpty());
 }
 
+TEST(StringUtilityTest, SplitDelimitedString)
+{
+    using ::testing::ElementsAre;
+    using ::testing::IsEmpty;
+    EXPECT_THAT(gmx::splitDelimitedString("foo;bar", ';'), ElementsAre("foo", "bar"));
+    EXPECT_THAT(gmx::splitDelimitedString(";foo;bar;", ';'), ElementsAre("", "foo", "bar", ""));
+    EXPECT_THAT(gmx::splitDelimitedString("foo;;bar", ';'), ElementsAre("foo", "", "bar"));
+    EXPECT_THAT(gmx::splitDelimitedString("foo", ';'), ElementsAre("foo"));
+    EXPECT_THAT(gmx::splitDelimitedString(";", ';'), ElementsAre("", ""));
+    EXPECT_THAT(gmx::splitDelimitedString("", ';'), IsEmpty());
+}
+
 /********************************************************************
  * Tests for formatString()
  */
diff --git a/src/gromacs/utility/variant.h b/src/gromacs/utility/variant.h
new file mode 100644 (file)
index 0000000..c130bdb
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares gmx::Variant.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+#ifndef GMX_UTILITY_VARIANT_H
+#define GMX_UTILITY_VARIANT_H
+
+#include <memory>
+#include <type_traits>
+#include <typeindex>
+#include <typeinfo>
+#include <utility>
+
+#include "gromacs/utility/gmxassert.h"
+
+namespace gmx
+{
+
+/*! \libinternal \brief
+ * Represents a dynamically typed value of an arbitrary type.
+ *
+ * To create a variant, either initialize it as empty, or with the create()
+ * method (or the equivalent constructor, if the type parameter can be deduced
+ * and is clear to the reader from the context).
+ *
+ * To query the type of the contents in the variant, use isEmpty(), type(), and
+ * isType().
+ *
+ * To access the value, you need to know the type as a compile-time constant
+ * (e.g., through branching based on isType()), and then use cast() or
+ * tryCast().
+ *
+ * Methods in this class do not throw unless otherwise indicated.
+ *
+ * This provides essentially the same functionality as boost::any.
+ *
+ * \ingroup module_utility
+ */
+class Variant
+{
+    public:
+        /*! \brief
+         * Creates a variant that holds the given value.
+         *
+         * \throws std::bad_alloc if out of memory.
+         *
+         * This method allows explicitly specifying the template argument,
+         * contrary to the templated constructor.
+         */
+        template <typename T>
+        static Variant create(const T &value) { return Variant(value); }
+        /*! \brief
+         * Creates a variant that holds the given value.
+         *
+         * \throws std::bad_alloc if out of memory.
+         *
+         * In addition to allowing specifying the template argument, this
+         * method avoids copying when move-construction is possible.
+         */
+        template <typename T>
+        static Variant create(T &&value) { return Variant(std::move(value)); }
+
+        //! Creates an empty variant value.
+        Variant() {}
+        /*! \brief
+         * Creates a variant that holds the given value.
+         *
+         * \throws std::bad_alloc if out of memory.
+         */
+        template <typename T>
+        explicit Variant(const T &value)
+            : content_(new Content<typename std::decay<T>::type>(value))
+        {
+        }
+        /*! \brief
+         * Creates a variant that holds the given value.
+         *
+         * \throws std::bad_alloc if out of memory.
+         */
+        template <typename T>
+        explicit Variant(T &&value)
+            : content_(new Content<typename std::decay<T>::type>(std::move(value)))
+        {
+        }
+        /*! \brief
+         * Creates a deep copy of a variant.
+         *
+         * \throws std::bad_alloc if out of memory.
+         */
+        Variant(const Variant &other) : content_(other.cloneContent()) {}
+        //! Move-constructs a variant.
+        Variant(Variant &&other) noexcept : content_(std::move(other.content_)) {}
+        /*! \brief
+         * Assigns the variant.
+         *
+         * \throws std::bad_alloc if out of memory.
+         */
+        Variant &operator=(const Variant &other)
+        {
+            content_.reset(other.cloneContent());
+            return *this;
+        }
+        //! Move-assigns the variant.
+        Variant &operator=(Variant &&other) noexcept
+        {
+            content_ = std::move(other.content_);
+            return *this;
+        }
+
+        //! Whether any value is stored.
+        bool isEmpty() const { return content_ == nullptr; }
+        //! Returns the dynamic type of the value that is currently stored.
+        std::type_index type() const
+        {
+            const std::type_info &info
+                = !isEmpty() ? content_->typeInfo() : typeid(void);
+            return std::type_index(info);
+        }
+        //! Returns whether the type stored matches the template parameter.
+        template <typename T>
+        bool isType() const
+        {
+            return !isEmpty() && content_->typeInfo() == typeid(T);
+        }
+
+        /*! \brief
+         * Tries to get the value as the given type.
+         *
+         * \tparam T  Type to get.
+         * \returns Pointer to the value, or nullptr if the type does not match
+         *     the stored value.
+         */
+        template <typename T>
+        const T *tryCast() const
+        {
+            return isType<T>() ? &static_cast<Content<T> *>(content_.get())->value_ : nullptr;
+        }
+        /*! \brief
+         * Gets the value when the type is known.
+         *
+         * \tparam T  Type to get (which must match what the variant stores).
+         *
+         * Asserts if the variant is empty or does not contain the requested type.
+         */
+        template <typename T>
+        const T &cast() const
+        {
+            const T *value = tryCast<T>();
+            GMX_RELEASE_ASSERT(value != nullptr, "Cast to incorrect type");
+            return *value;
+        }
+        /*! \brief
+         * Tries to get the value as the given type as a non-const pointer.
+         *
+         * \tparam T  Type to get.
+         * \returns Pointer to the value, or nullptr if the type does not match
+         *     the stored value.
+         *
+         * This method allows modifying the value in-place, which is useful
+         * with more complicated data structures.
+         */
+        template <typename T>
+        T *tryCastRef()
+        {
+            return isType<T>() ? &static_cast<Content<T> *>(content_.get())->value_ : nullptr;
+        }
+        /*! \brief
+         * Gets the value when the type is known as a modifiable reference.
+         *
+         * \tparam T  Type to get (which must match what the variant stores).
+         *
+         * Asserts if the variant is empty or does not contain the requested type.
+         */
+        template <typename T>
+        T &castRef()
+        {
+            T *value = tryCastRef<T>();
+            GMX_RELEASE_ASSERT(value != nullptr, "Cast to incorrect type");
+            return *value;
+        }
+
+    private:
+        class IContent
+        {
+            public:
+                virtual ~IContent() {}
+                virtual const std::type_info &typeInfo() const = 0;
+                virtual IContent *clone() const                = 0;
+        };
+
+        template <typename T>
+        class Content : public IContent
+        {
+            public:
+                explicit Content(const T &value) : value_(value) {}
+                explicit Content(T &&value) : value_(std::move(value)) {}
+
+                virtual const std::type_info &typeInfo() const { return typeid(T); }
+                virtual IContent *clone() const { return new Content(value_); }
+
+                T value_;
+        };
+
+        //! Creates a deep copy of the content.
+        IContent *cloneContent() const
+        {
+            return content_ != nullptr ? content_->clone() : nullptr;
+        }
+
+        std::unique_ptr<IContent> content_;
+};
+
+} // namespace gmx
+
+#endif
index 16590b6d18b30e2869aa3f535b326c7ebde50619..81e7e293014bd0b990f8302a17d21feed4fe1029 100644 (file)
@@ -41,9 +41,13 @@ if(GMX_FAHCORE)
     # may break some generators, according to CMake documentation. If
     # so, we can consider adding some dummy file to make it work.
     add_library(fahcore $<TARGET_OBJECTS:mdrun_objlib>)
+    target_link_libraries(fahcore PRIVATE ${GMX_COMMON_LIBRARIES})
 elseif(GMX_BUILD_MDRUN_ONLY)
     add_executable(mdrun $<TARGET_OBJECTS:mdrun_objlib> mdrun_main.cpp)
-    target_link_libraries(mdrun libgromacs ${GMX_EXE_LINKER_FLAGS} ${GMX_STDLIB_LIBRARIES})
+    target_link_libraries(mdrun libgromacs
+        ${GMX_COMMON_LIBRARIES}
+        ${GMX_EXE_LINKER_FLAGS}
+        ${GMX_STDLIB_LIBRARIES})
     set(BINARY_NAME "mdrun${GMX_BINARY_SUFFIX}")
     set_target_properties(mdrun PROPERTIES
         OUTPUT_NAME "${BINARY_NAME}"
@@ -65,7 +69,10 @@ else()
         ${GMX_MAIN_SOURCES}
         $<TARGET_OBJECTS:mdrun_objlib>
         $<TARGET_OBJECTS:view_objlib>)
-    target_link_libraries(gmx libgromacs ${GMX_EXE_LINKER_FLAGS} ${GMX_STDLIB_LIBRARIES})
+    target_link_libraries(gmx libgromacs
+        ${GMX_COMMON_LIBRARIES}
+        ${GMX_EXE_LINKER_FLAGS}
+        ${GMX_STDLIB_LIBRARIES})
     if(GMX_X11)
         target_link_libraries(gmx ${X11_LIBRARIES})
     endif()
index 06c25f321404e012b870cfff79c5044308431b7e..29d96431d32446f64a1deeac5eb3fa53e33502dc 100644 (file)
@@ -45,6 +45,7 @@
 #include <stdlib.h>
 
 #include <algorithm>
+#include <memory>
 
 #include "thread_mpi/threads.h"
 
@@ -55,7 +56,6 @@
 #include "gromacs/ewald/pme.h"
 #include "gromacs/ewald/pme-load-balancing.h"
 #include "gromacs/fileio/trxio.h"
-#include "gromacs/gmxlib/md_logging.h"
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/gmxlib/nrnb.h"
 #include "gromacs/gpu_utils/gpu_utils.h"
@@ -76,6 +76,7 @@
 #include "gromacs/mdlib/mdebin.h"
 #include "gromacs/mdlib/mdoutf.h"
 #include "gromacs/mdlib/mdrun.h"
+#include "gromacs/mdlib/mdsetup.h"
 #include "gromacs/mdlib/nb_verlet.h"
 #include "gromacs/mdlib/nbnxn_gpu_data_mgmt.h"
 #include "gromacs/mdlib/ns.h"
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/logger.h"
 #include "gromacs/utility/real.h"
 #include "gromacs/utility/smalloc.h"
 
@@ -153,7 +155,7 @@ static void checkNumberOfBondedInteractions(FILE *fplog, t_commrec *cr, int tota
     }
 }
 
-static void reset_all_counters(FILE *fplog, t_commrec *cr,
+static void reset_all_counters(FILE *fplog, const gmx::MDLogger &mdlog, t_commrec *cr,
                                gmx_int64_t step,
                                gmx_int64_t *step_rel, t_inputrec *ir,
                                gmx_wallcycle_t wcycle, t_nrnb *nrnb,
@@ -163,8 +165,9 @@ static void reset_all_counters(FILE *fplog, t_commrec *cr,
     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));
+    GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+            "step %s: resetting all time and cycle counters",
+            gmx_step_str(step, sbuf));
 
     if (use_GPU(nbv))
     {
@@ -188,7 +191,7 @@ static void reset_all_counters(FILE *fplog, t_commrec *cr,
 }
 
 /*! \libinternal
-    \copydoc integrator_t (FILE *fplog, t_commrec *cr,
+    \copydoc integrator_t (FILE *fplog, t_commrec *cr, const gmx::MDLogger &mdlog,
                            int nfile, const t_filenm fnm[],
                            const gmx_output_env_t *oenv, gmx_bool bVerbose,
                            int nstglobalcomm,
@@ -207,7 +210,8 @@ static void reset_all_counters(FILE *fplog, t_commrec *cr,
                            unsigned long Flags,
                            gmx_walltime_accounting_t walltime_accounting)
  */
-double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
+double gmx::do_md(FILE *fplog, t_commrec *cr, const gmx::MDLogger &mdlog,
+                  int nfile, const t_filenm fnm[],
                   const gmx_output_env_t *oenv, gmx_bool bVerbose,
                   int nstglobalcomm,
                   gmx_vsite_t *vsite, gmx_constr_t constr,
@@ -215,6 +219,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
                   gmx_mtop_t *top_global,
                   t_fcdata *fcd,
                   t_state *state_global,
+                  energyhistory_t *energyHistory,
                   t_mdatoms *mdatoms,
                   t_nrnb *nrnb, gmx_wallcycle_t wcycle,
                   gmx_edsam_t ed, t_forcerec *fr,
@@ -243,15 +248,14 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
     t_trxstatus      *status;
     rvec              mu_tot;
     t_vcm            *vcm;
-    matrix            pcoupl_mu, M;
+    matrix            parrinellorahmanMu, M;
     t_trxframe        rerun_fr;
     gmx_repl_ex_t     repl_ex = NULL;
     int               nchkpt  = 1;
     gmx_localtop_t   *top;
     t_mdebin         *mdebin   = NULL;
-    t_state          *state    = NULL;
     gmx_enerdata_t   *enerd;
-    rvec             *f = NULL;
+    PaddedRVecVector  f {};
     gmx_global_stat_t gstat;
     gmx_update_t     *upd   = NULL;
     t_graph          *graph = NULL;
@@ -331,7 +335,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
         nstglobalcomm     = 1;
     }
 
-    nstglobalcomm   = check_nstglobalcomm(fplog, cr, nstglobalcomm, ir);
+    nstglobalcomm   = check_nstglobalcomm(mdlog, nstglobalcomm, ir);
     bGStatEveryStep = (nstglobalcomm == 1);
 
     if (bRerunMD)
@@ -344,11 +348,11 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
     {
         /* Initialize ion swapping code */
         init_swapcoords(fplog, bVerbose, ir, opt2fn_master("-swap", nfile, fnm, cr),
-                        top_global, state_global->x, state_global->box, &state_global->swapstate, cr, oenv, Flags);
+                        top_global, as_rvec_array(state_global->x.data()), state_global->box, &state_global->swapstate, cr, oenv, Flags);
     }
 
     /* Initial values */
-    init_md(fplog, cr, ir, oenv, &t, &t0, state_global->lambda,
+    init_md(fplog, cr, ir, oenv, &t, &t0, &state_global->lambda,
             &(state_global->fep_state), lam0,
             nrnb, top_global, &upd,
             nfile, fnm, &outf, &mdebin,
@@ -360,13 +364,9 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
     snew(enerd, 1);
     init_enerdata(top_global->groups.grps[egcENER].nr, ir->fepvals->n_lambda,
                   enerd);
-    if (DOMAINDECOMP(cr))
-    {
-        f = NULL;
-    }
-    else
+    if (!DOMAINDECOMP(cr))
     {
-        snew(f, top_global->natoms);
+        f.resize(top_global->natoms + 1);
     }
 
     /* Kinetic energy data */
@@ -410,43 +410,31 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
         }
     }
 
+    std::unique_ptr<t_state> stateInstance;
+    t_state *                state;
+
     if (DOMAINDECOMP(cr))
     {
         top = dd_init_local_top(top_global);
 
-        snew(state, 1);
+        stateInstance = std::unique_ptr<t_state>(new t_state {});
+        state         = stateInstance.get();
         dd_init_local_state(cr->dd, state_global, state);
     }
     else
     {
-        top = gmx_mtop_generate_local_top(top_global, ir->efep != efepNO);
-
-        state    = serial_init_local_state(state_global);
+        /* Copy the pointer to the global state */
+        state = state_global;
 
-        atoms2md(top_global, ir, 0, NULL, top_global->natoms, mdatoms);
+        snew(top, 1);
+        mdAlgorithmsSetupAtomData(cr, ir, top_global, top, fr,
+                                  &graph, mdatoms, vsite, shellfc);
 
-        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);
-        }
-
-        setup_bonded_threading(fr, &top->idef);
-
-        update_realloc(upd, state->nalloc);
+        update_realloc(upd, state->natoms);
     }
 
     /* Set up interactive MD (IMD) */
-    init_IMD(ir, cr, top_global, fplog, ir->nstcalcenergy, state_global->x,
+    init_IMD(ir, cr, top_global, fplog, ir->nstcalcenergy, as_rvec_array(state_global->x.data()),
              nfile, fnm, oenv, imdport, Flags);
 
     if (DOMAINDECOMP(cr))
@@ -458,7 +446,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
                             vsite, constr,
                             nrnb, NULL, FALSE);
         shouldCheckNumberOfBondedInteractions = true;
-        update_realloc(upd, state->nalloc);
+        update_realloc(upd, state->natoms);
     }
 
     update_mdatoms(mdatoms, state->lambda[efptMASS]);
@@ -467,7 +455,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
 
     if (ir->bExpanded)
     {
-        init_expanded_ensemble(startingFromCheckpoint, ir, &state->dfhist);
+        init_expanded_ensemble(startingFromCheckpoint, ir, state->dfhist);
     }
 
     if (MASTER(cr))
@@ -477,19 +465,18 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
             /* Update mdebin with energy history if appending to output files */
             if (Flags & MD_APPENDFILES)
             {
-                restore_energyhistory_from_state(mdebin, state_global->enerhist);
+                restore_energyhistory_from_state(mdebin, energyHistory);
             }
             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);
+                *energyHistory = {};
             }
         }
         /* Set the initial energy history in state by updating once */
-        update_energyhistory(state_global->enerhist, mdebin);
+        update_energyhistory(energyHistory, mdebin);
     }
 
     /* Initialize constraints */
@@ -511,23 +498,31 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
                 !(Flags & MD_REPRODUCIBLE));
     if (bPMETune)
     {
-        pme_loadbal_init(&pme_loadbal, cr, fplog, ir, state->box,
+        pme_loadbal_init(&pme_loadbal, cr, mdlog, ir, state->box,
                          fr->ic, fr->pmedata, use_GPU(fr->nbv),
                          &bPMETunePrinting);
     }
 
     if (!ir->bContinuation && !bRerunMD)
     {
-        if (mdatoms->cFREEZE && (state->flags & (1<<estV)))
+        if (state->flags & (1 << estV))
         {
-            /* Set the velocities of frozen particles to zero */
+            /* Set the velocities of vsites, shells and frozen atoms to zero */
             for (i = 0; i < mdatoms->homenr; i++)
             {
-                for (m = 0; m < DIM; m++)
+                if (mdatoms->ptype[i] == eptVSite ||
+                    mdatoms->ptype[i] == eptShell)
                 {
-                    if (ir->opts.nFreeze[mdatoms->cFREEZE[i]][m])
+                    clear_rvec(state->v[i]);
+                }
+                else if (mdatoms->cFREEZE)
+                {
+                    for (m = 0; m < DIM; m++)
                     {
-                        state->v[i][m] = 0;
+                        if (ir->opts.nFreeze[mdatoms->cFREEZE[i]][m])
+                        {
+                            state->v[i][m] = 0;
+                        }
                     }
                 }
             }
@@ -542,7 +537,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
         if (vsite)
         {
             /* Construct the virtual sites for the initial configuration */
-            construct_vsites(vsite, state->x, ir->delta_t, NULL,
+            construct_vsites(vsite, as_rvec_array(state->x.data()), ir->delta_t, NULL,
                              top->idef.iparams, top->idef.il,
                              fr->ePBC, fr->bMolPBC, cr, state->box);
         }
@@ -776,15 +771,15 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
     {
         if (!multisim_int_all_are_equal(cr->ms, ir->nsteps))
         {
-            md_print_info(cr, fplog,
-                          "Note: The number of steps is not consistent across multi simulations,\n"
-                          "but we are proceeding anyway!\n");
+            GMX_LOG(mdlog.warning).appendText(
+                    "Note: The number of steps is not consistent across multi simulations,\n"
+                    "but we are proceeding anyway!");
         }
         if (!multisim_int_all_are_equal(cr->ms, ir->init_step))
         {
-            md_print_info(cr, fplog,
-                          "Note: The initial step is not consistent across multi simulations,\n"
-                          "but we are proceeding anyway!\n");
+            GMX_LOG(mdlog.warning).appendText(
+                    "Note: The initial step is not consistent across multi simulations,\n"
+                    "but we are proceeding anyway!");
         }
     }
 
@@ -801,7 +796,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
             /* PME grid + cut-off optimization with GPUs or PME nodes */
             pme_loadbal_do(pme_loadbal, cr,
                            (bVerbose && MASTER(cr)) ? stderr : NULL,
-                           fplog,
+                           fplog, mdlog,
                            ir, fr, state,
                            wcycle,
                            step, step_rel,
@@ -898,15 +893,15 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
                     /* 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);
+                    mk_mshift(fplog, graph, fr->ePBC, state->box, as_rvec_array(state->x.data()));
+                    shift_self(graph, state->box, as_rvec_array(state->x.data()));
                 }
-                construct_vsites(vsite, state->x, ir->delta_t, state->v,
+                construct_vsites(vsite, as_rvec_array(state->x.data()), ir->delta_t, as_rvec_array(state->v.data()),
                                  top->idef.iparams, top->idef.il,
                                  fr->ePBC, fr->bMolPBC, cr, state->box);
                 if (graph)
                 {
-                    unshift_self(graph, state->box, state->x);
+                    unshift_self(graph, state->box, as_rvec_array(state->x.data()));
                 }
             }
         }
@@ -983,7 +978,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
                                     nrnb, wcycle,
                                     do_verbose && !bPMETunePrinting);
                 shouldCheckNumberOfBondedInteractions = true;
-                update_realloc(upd, state->nalloc);
+                update_realloc(upd, state->natoms);
             }
         }
 
@@ -1077,10 +1072,10 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
             relax_shell_flexcon(fplog, cr, bVerbose, step,
                                 ir, bNS, force_flags, top,
                                 constr, enerd, fcd,
-                                state, f, force_vir, mdatoms,
+                                state, &f, force_vir, mdatoms,
                                 nrnb, wcycle, graph, groups,
                                 shellfc, fr, bBornRadii, t, mu_tot,
-                                vsite, mdoutf_get_fp_field(outf));
+                                vsite);
         }
         else
         {
@@ -1090,10 +1085,10 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
              * Check comments in sim_util.c
              */
             do_force(fplog, cr, ir, step, nrnb, wcycle, top, groups,
-                     state->box, state->x, &state->hist,
-                     f, force_vir, mdatoms, enerd, fcd,
-                     state->lambda, graph,
-                     fr, vsite, mu_tot, t, mdoutf_get_fp_field(outf), ed, bBornRadii,
+                     state->box, &state->x, &state->hist,
+                     &f, force_vir, mdatoms, enerd, fcd,
+                     &state->lambda, graph,
+                     fr, vsite, mu_tot, t, ed, bBornRadii,
                      (bNS ? GMX_FORCE_NS : 0) | force_flags);
         }
 
@@ -1112,7 +1107,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
                  * so that the input is actually the initial step.
                  */
                 snew(vbuf, state->natoms);
-                copy_rvecn(state->v, vbuf, 0, state->natoms); /* should make this better for parallelizing? */
+                copy_rvecn(as_rvec_array(state->v.data()), vbuf, 0, state->natoms); /* should make this better for parallelizing? */
             }
             else
             {
@@ -1120,7 +1115,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
                 trotter_update(ir, step, ekind, enerd, state, total_vir, mdatoms, &MassQ, trotter_seq, ettTSEQ1);
             }
 
-            update_coords(fplog, step, ir, mdatoms, state, f, fcd,
+            update_coords(fplog, step, ir, mdatoms, state, &f, fcd,
                           ekind, M, upd, etrtVELOCITY1,
                           cr, constr);
 
@@ -1128,7 +1123,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
             {
                 wallcycle_stop(wcycle, ewcUPDATE);
                 update_constraints(fplog, step, NULL, ir, mdatoms,
-                                   state, fr->bMolPBC, graph, f,
+                                   state, fr->bMolPBC, graph, &f,
                                    &top->idef, shake_vir,
                                    cr, nrnb, wcycle, upd, constr,
                                    TRUE, bCalcVir);
@@ -1138,7 +1133,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
             {
                 /* Need to unshift here if a do_force has been
                    called in the previous step */
-                unshift_self(graph, state->box, state->x);
+                unshift_self(graph, state->box, as_rvec_array(state->x.data()));
             }
             /* if VV, compute the pressure and constraints */
             /* For VV2, we strictly only need this if using pressure
@@ -1219,7 +1214,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
             /* if it's the initial step, we performed this first step just to get the constraint virial */
             if (ir->eI == eiVV && bInitStep)
             {
-                copy_rvecn(vbuf, state->v, 0, state->natoms);
+                copy_rvecn(vbuf, as_rvec_array(state->v.data()), 0, state->natoms);
                 sfree(vbuf);
             }
             wallcycle_stop(wcycle, ewcUPDATE);
@@ -1228,7 +1223,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
         /* compute the conserved quantity */
         if (EI_VV(ir->eI))
         {
-            saved_conserved_quantity = compute_conserved_from_auxiliary(ir, state, &MassQ);
+            saved_conserved_quantity = NPT_energy(ir, state, &MassQ);
             if (ir->eI == eiVV)
             {
                 last_ekin = enerd->term[F_EKIN];
@@ -1240,7 +1235,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
             /* sum up the foreign energy and dhdl terms for vv.  currently done every step so that dhdl is correct in the .edr */
             if (ir->efep != efepNO && !bRerunMD)
             {
-                sum_dhdl(enerd, state->lambda, ir->fepvals);
+                sum_dhdl(enerd, &state->lambda, ir->fepvals);
             }
         }
 
@@ -1253,9 +1248,9 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
                statistics, but if performing simulated tempering, we
                do update the velocities and the tau_t. */
 
-            lamnew = ExpandedEnsembleDynamics(fplog, ir, enerd, state, &MassQ, state->fep_state, &state->dfhist, step, state->v, mdatoms);
+            lamnew = ExpandedEnsembleDynamics(fplog, ir, enerd, state, &MassQ, state->fep_state, state->dfhist, step, as_rvec_array(state->v.data()), mdatoms);
             /* history is maintained in state->dfhist, but state_global is what is sent to trajectory and log output */
-            copy_df_history(&state_global->dfhist, &state->dfhist);
+            copy_df_history(state_global->dfhist, state->dfhist);
         }
 
         /* Now we have the energies and forces corresponding to the
@@ -1263,13 +1258,14 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
          * the update.
          */
         do_md_trajectory_writing(fplog, cr, nfile, fnm, step, step_rel, t,
-                                 ir, state, state_global, top_global, fr,
-                                 outf, mdebin, ekind, f,
+                                 ir, state, state_global, energyHistory,
+                                 top_global, fr,
+                                 outf, mdebin, ekind, &f,
                                  &nchkpt,
                                  bCPT, bRerunMD, bLastStep, (Flags & MD_CONFOUT),
                                  bSumEkinhOld);
         /* Check if IMD step and do IMD communication, if bIMD is TRUE. */
-        bIMDstep = do_IMD(ir->bIMD, step, cr, bNS, state->box, state->x, ir, t, wcycle);
+        bIMDstep = do_IMD(ir->bIMD, step, cr, bNS, state->box, as_rvec_array(state->x.data()), ir, t, wcycle);
 
         /* kludge -- virial is lost with restart for MTTK NPT control. Must reload (saved earlier). */
         if (startingFromCheckpoint && bTrotter)
@@ -1361,7 +1357,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
             if (constr && bIfRandomize)
             {
                 update_constraints(fplog, step, NULL, ir, mdatoms,
-                                   state, fr->bMolPBC, graph, f,
+                                   state, fr->bMolPBC, graph, &f,
                                    &top->idef, tmp_vir,
                                    cr, nrnb, wcycle, upd, constr,
                                    TRUE, bCalcVir);
@@ -1392,13 +1388,15 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
             else
             {
                 update_tcouple(step, ir, state, ekind, &MassQ, mdatoms);
-                update_pcouple(fplog, step, ir, state, pcoupl_mu, M, bInitStep);
+                update_pcouple_before_coordinates(fplog, step, ir, state,
+                                                  parrinellorahmanMu, M,
+                                                  bInitStep);
             }
 
             if (EI_VV(ir->eI))
             {
                 /* velocity half-step update */
-                update_coords(fplog, step, ir, mdatoms, state, f, fcd,
+                update_coords(fplog, step, ir, mdatoms, state, &f, fcd,
                               ekind, M, upd, etrtVELOCITY2,
                               cr, constr);
             }
@@ -1416,15 +1414,15 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
                     cbuf_nalloc = state->natoms;
                     srenew(cbuf, cbuf_nalloc);
                 }
-                copy_rvecn(state->x, cbuf, 0, state->natoms);
+                copy_rvecn(as_rvec_array(state->x.data()), cbuf, 0, state->natoms);
             }
 
-            update_coords(fplog, step, ir, mdatoms, state, f, fcd,
+            update_coords(fplog, step, ir, mdatoms, state, &f, fcd,
                           ekind, M, upd, etrtPOSITION, cr, constr);
             wallcycle_stop(wcycle, ewcUPDATE);
 
             update_constraints(fplog, step, &dvdl_constr, ir, mdatoms, state,
-                               fr->bMolPBC, graph, f,
+                               fr->bMolPBC, graph, &f,
                                &top->idef, shake_vir,
                                cr, nrnb, wcycle, upd, constr,
                                FALSE, bCalcVir);
@@ -1442,19 +1440,19 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
                 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);
+                copy_rvecn(cbuf, as_rvec_array(state->x.data()), 0, state->natoms);
 
-                update_coords(fplog, step, ir, mdatoms, state, f, fcd,
+                update_coords(fplog, step, ir, mdatoms, state, &f, fcd,
                               ekind, M, upd, etrtPOSITION, cr, constr);
                 wallcycle_stop(wcycle, ewcUPDATE);
 
-                /* do we need an extra constraint here? just need to copy out of state->v to upd->xp? */
+                /* do we need an extra constraint here? just need to copy out of as_rvec_array(state->v.data()) 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, NULL, ir, mdatoms,
-                                   state, fr->bMolPBC, graph, f,
+                                   state, fr->bMolPBC, graph, &f,
                                    &top->idef, tmp_vir,
                                    cr, nrnb, wcycle, upd, NULL,
                                    FALSE, bCalcVir);
@@ -1485,7 +1483,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
         else if (graph)
         {
             /* Need to unshift here */
-            unshift_self(graph, state->box, state->x);
+            unshift_self(graph, state->box, as_rvec_array(state->x.data()));
         }
 
         if (vsite != NULL)
@@ -1493,15 +1491,15 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
             wallcycle_start(wcycle, ewcVSITECONSTR);
             if (graph != NULL)
             {
-                shift_self(graph, state->box, state->x);
+                shift_self(graph, state->box, as_rvec_array(state->x.data()));
             }
-            construct_vsites(vsite, state->x, ir->delta_t, state->v,
+            construct_vsites(vsite, as_rvec_array(state->x.data()), ir->delta_t, as_rvec_array(state->v.data()),
                              top->idef.iparams, top->idef.il,
                              fr->ePBC, fr->bMolPBC, cr, state->box);
 
             if (graph != NULL)
             {
-                unshift_self(graph, state->box, state->x);
+                unshift_self(graph, state->box, as_rvec_array(state->x.data()));
             }
             wallcycle_stop(wcycle, ewcVSITECONSTR);
         }
@@ -1558,10 +1556,12 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
         {
             /* 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);
+            sum_dhdl(enerd, &state->lambda, ir->fepvals);
         }
-        update_box(fplog, step, ir, mdatoms, state, f,
-                   pcoupl_mu, nrnb, upd);
+
+        update_pcouple_after_coordinates(fplog, step, ir, mdatoms,
+                                         pres, parrinellorahmanMu,
+                                         state, nrnb, upd);
 
         /* ################# END UPDATE STEP 2 ################# */
         /* #### We now have r(t+dt) and v(t+dt/2)  ############# */
@@ -1590,7 +1590,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
         }
         else
         {
-            enerd->term[F_ECONSERVED] = enerd->term[F_ETOT] + compute_conserved_from_auxiliary(ir, state, &MassQ);
+            enerd->term[F_ECONSERVED] = enerd->term[F_ETOT] + NPT_energy(ir, state, &MassQ);
         }
         /* #########  END PREPARING EDR OUTPUT  ###########  */
 
@@ -1601,7 +1601,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
             {
                 /* only needed if doing expanded ensemble */
                 PrintFreeEnergyInfoToFile(fplog, ir->fepvals, ir->expandedvals, ir->bSimTemp ? ir->simtempvals : NULL,
-                                          &state_global->dfhist, state->fep_state, ir->nstlog, step);
+                                          state_global->dfhist, state->fep_state, ir->nstlog, step);
             }
             if (bCalcEner)
             {
@@ -1662,9 +1662,9 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
             do_per_step(step, ir->swap->nstswap))
         {
             bNeedRepartition = do_swapcoords(cr, step, t, ir, wcycle,
-                                             bRerunMD ? rerun_fr.x   : state->x,
+                                             bRerunMD ? rerun_fr.x   : as_rvec_array(state->x.data()),
                                              bRerunMD ? rerun_fr.box : state->box,
-                                             top_global, MASTER(cr) && bVerbose, bRerunMD);
+                                             MASTER(cr) && bVerbose, bRerunMD);
 
             if (bNeedRepartition && DOMAINDECOMP(cr))
             {
@@ -1689,7 +1689,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
                                 vsite, constr,
                                 nrnb, wcycle, FALSE);
             shouldCheckNumberOfBondedInteractions = true;
-            update_realloc(upd, state->nalloc);
+            update_realloc(upd, state->natoms);
         }
 
         bFirstStep             = FALSE;
@@ -1714,7 +1714,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
 
         if ( (membed != NULL) && (!bLastStep) )
         {
-            rescale_membed(step_rel, membed, state_global->x);
+            rescale_membed(step_rel, membed, as_rvec_array(state_global->x.data()));
         }
 
         if (bRerunMD)
@@ -1766,7 +1766,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
                           "resetting counters later in the run, e.g. with gmx "
                           "mdrun -resetstep.", step);
             }
-            reset_all_counters(fplog, cr, step, &step_rel, ir, wcycle, nrnb, walltime_accounting,
+            reset_all_counters(fplog, mdlog, cr, step, &step_rel, ir, wcycle, nrnb, walltime_accounting,
                                use_GPU(fr->nbv) ? fr->nbv : NULL);
             wcycle_set_reset_counters(wcycle, -1);
             if (!(cr->duty & DUTY_PME))
@@ -1815,11 +1815,11 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
         }
     }
 
-    done_mdoutf(outf);
+    done_mdoutf(outf, ir);
 
     if (bPMETune)
     {
-        pme_loadbal_done(pme_loadbal, cr, fplog, use_GPU(fr->nbv));
+        pme_loadbal_done(pme_loadbal, fplog, mdlog, use_GPU(fr->nbv));
     }
 
     done_shellfc(fplog, shellfc, step_rel);
index 7829a823a444275ed73b151559277993c710e31e..4d937a3b6260f5565cff47af633d45d64a16a738 100644 (file)
@@ -67,6 +67,7 @@
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/utility/arraysize.h"
 #include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/smalloc.h"
 
 #include "mdrun_main.h"
 #include "runner.h"
@@ -156,7 +157,8 @@ int gmx_mdrun(int argc, char *argv[])
         "The option [TT]-pforce[tt] is useful when you suspect a simulation",
         "crashes due to too large forces. With this option coordinates and",
         "forces of atoms with a force larger than a certain value will",
-        "be printed to stderr.",
+        "be printed to stderr. It will also terminate the run when non-finite",
+        "forces are present.",
         "[PAR]",
         "Checkpoints containing the complete state of the system are written",
         "at regular intervals (option [TT]-cpt[tt]) to the file [TT]-cpo[tt],",
@@ -449,6 +451,7 @@ int gmx_mdrun(int argc, char *argv[])
     if (!parse_common_args(&argc, argv, PCA_Flags, NFILE, fnm, asize(pa), pa,
                            asize(desc), desc, 0, NULL, &oenv))
     {
+        sfree(cr);
         return 0;
     }
 
index 50feee655d4e9e66f98eb854ca998dfddbbed99c..ce15054cf88be6b169668a73a088d8b695b5f74d 100644 (file)
@@ -50,6 +50,7 @@
 #include "gromacs/mdtypes/state.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/topology/index.h"
+#include "gromacs/topology/mtop_lookup.h"
 #include "gromacs/topology/mtop_util.h"
 #include "gromacs/topology/topology.h"
 #include "gromacs/utility/cstringutil.h"
@@ -106,18 +107,15 @@ static int get_mol_id(int at, gmx_mtop_t  *mtop, int *type, int *block)
     int                   mol_id = 0;
     int                   i;
     int                   atnr_mol;
-    gmx_mtop_atomlookup_t alook;
 
-    alook = gmx_mtop_atomlookup_settle_init(mtop);
-    gmx_mtop_atomnr_to_molblock_ind(alook, at, block, &mol_id, &atnr_mol);
+    *block = 0;
+    mtopGetMolblockIndex(mtop, at, block, &mol_id, &atnr_mol);
     for (i = 0; i < *block; i++)
     {
         mol_id += mtop->molblock[i].nmol;
     }
     *type = mtop->molblock[*block].type;
 
-    gmx_mtop_atomlookup_destroy(alook);
-
     return mol_id;
 }
 
@@ -721,9 +719,8 @@ static void rm_group(gmx_groups_t *groups, gmx_mtop_t *mtop, rm_t *rm_p, t_state
     mtop->mols.index = new_mols;
     mtop->natoms    -= n;
     state->natoms   -= n;
-    state->nalloc    = state->natoms;
-    snew(x_tmp, state->nalloc);
-    snew(v_tmp, state->nalloc);
+    snew(x_tmp, state->natoms);
+    snew(v_tmp, state->natoms);
 
     for (i = 0; i < egcNR; i++)
     {
@@ -778,10 +775,16 @@ static void rm_group(gmx_groups_t *groups, gmx_mtop_t *mtop, rm_t *rm_p, t_state
             }
         }
     }
-    sfree(state->x);
-    state->x = x_tmp;
-    sfree(state->v);
-    state->v = v_tmp;
+    for (int i = 0; i < state->natoms; i++)
+    {
+        copy_rvec(x_tmp[i], state->x[i]);
+    }
+    sfree(x_tmp);
+    for (int i = 0; i < state->natoms; i++)
+    {
+        copy_rvec(v_tmp[i], state->v[i]);
+    }
+    sfree(v_tmp);
 
     for (i = 0; i < egcNR; i++)
     {
@@ -1203,9 +1206,9 @@ gmx_membed_t *init_membed(FILE *fplog, int nfile, const t_filenm fnm[], gmx_mtop
         /* Check that moleculetypes in insertion group are not part of the rest of the system */
         check_types(ins_at, rest_at, mtop);
 
-        init_mem_at(mem_p, mtop, state->x, state->box, pos_ins);
+        init_mem_at(mem_p, mtop, as_rvec_array(state->x.data()), state->box, pos_ins);
 
-        prot_area = est_prot_area(pos_ins, state->x, ins_at, mem_p);
+        prot_area = est_prot_area(pos_ins, as_rvec_array(state->x.data()), ins_at, mem_p);
         if ( (prot_area > prot_vs_box) && ( (state->box[XX][XX]*state->box[YY][YY]-state->box[XX][YY]*state->box[YY][XX]) < box_vs_prot) )
         {
             warn++;
@@ -1235,14 +1238,14 @@ gmx_membed_t *init_membed(FILE *fplog, int nfile, const t_filenm fnm[], gmx_mtop
 
         /* resize the protein by xy and by z if necessary*/
         snew(r_ins, ins_at->nr);
-        init_resize(ins_at, r_ins, pos_ins, mem_p, state->x, bALLOW_ASYMMETRY);
+        init_resize(ins_at, r_ins, pos_ins, mem_p, as_rvec_array(state->x.data()), bALLOW_ASYMMETRY);
         membed->fac[0] = membed->fac[1] = xy_fac;
         membed->fac[2] = z_fac;
 
         membed->xy_step = (xy_max-xy_fac)/(double)(it_xy);
         membed->z_step  = (z_max-z_fac)/(double)(it_z-1);
 
-        resize(r_ins, state->x, pos_ins, membed->fac);
+        resize(r_ins, as_rvec_array(state->x.data()), pos_ins, membed->fac);
 
         /* remove overlapping lipids and water from the membrane box*/
         /*mark molecules to be removed*/
@@ -1250,7 +1253,7 @@ gmx_membed_t *init_membed(FILE *fplog, int nfile, const t_filenm fnm[], gmx_mtop
         set_pbc(pbc, inputrec->ePBC, state->box);
 
         snew(rm_p, 1);
-        lip_rm = gen_rm_list(rm_p, ins_at, rest_at, pbc, mtop, state->x, mem_p, pos_ins,
+        lip_rm = gen_rm_list(rm_p, ins_at, rest_at, pbc, mtop, as_rvec_array(state->x.data()), mem_p, pos_ins,
                              probe_rad, low_up_rm, bALLOW_ASYMMETRY);
         lip_rm -= low_up_rm;
 
index a3d89573f6936e2821da63f792bd7caed3a53537..83c1e43a23c5d774b827cc6f9ec397514c9f0b8d 100644 (file)
@@ -542,102 +542,32 @@ static void exchange_state(const gmx_multisim_t *ms, int b, t_state *state)
     exchange_rvecs(ms, b, state->svir_prev, DIM);
     exchange_rvecs(ms, b, state->fvir_prev, DIM);
     exchange_rvecs(ms, b, state->pres_prev, DIM);
-    exchange_doubles(ms, b, state->nosehoover_xi, ngtc);
-    exchange_doubles(ms, b, state->nosehoover_vxi, ngtc);
-    exchange_doubles(ms, b, state->nhpres_xi, nnhpres);
-    exchange_doubles(ms, b, state->nhpres_vxi, nnhpres);
-    exchange_doubles(ms, b, state->therm_integral, state->ngtc);
-    exchange_rvecs(ms, b, state->x, state->natoms);
-    exchange_rvecs(ms, b, state->v, state->natoms);
+    exchange_doubles(ms, b, state->nosehoover_xi.data(), ngtc);
+    exchange_doubles(ms, b, state->nosehoover_vxi.data(), ngtc);
+    exchange_doubles(ms, b, state->nhpres_xi.data(), nnhpres);
+    exchange_doubles(ms, b, state->nhpres_vxi.data(), nnhpres);
+    exchange_doubles(ms, b, state->therm_integral.data(), state->ngtc);
+    exchange_rvecs(ms, b, as_rvec_array(state->x.data()), state->natoms);
+    exchange_rvecs(ms, b, as_rvec_array(state->v.data()), state->natoms);
 }
 
-static void copy_rvecs(rvec *s, rvec *d, int n)
+static void copy_state_serial(const t_state *src, t_state *dest)
 {
-    int i;
-
-    if (d != NULL)
-    {
-        for (i = 0; i < n; i++)
-        {
-            copy_rvec(s[i], d[i]);
-        }
-    }
-}
-
-static void copy_doubles(const double *s, double *d, int n)
-{
-    int i;
-
-    if (d != NULL)
-    {
-        for (i = 0; i < n; i++)
-        {
-            d[i] = s[i];
-        }
-    }
-}
-
-static void copy_reals(const real *s, real *d, int n)
-{
-    int i;
-
-    if (d != NULL)
+    if (dest != src)
     {
-        for (i = 0; i < n; i++)
-        {
-            d[i] = s[i];
-        }
-    }
-}
-
-static void copy_ints(const int *s, int *d, int n)
-{
-    int i;
-
-    if (d != NULL)
-    {
-        for (i = 0; i < n; i++)
-        {
-            d[i] = s[i];
-        }
+        /* Currently the local state is always a pointer to the global
+         * in serial, so we should never end up here.
+         * TODO: Implement a (trivial) t_state copy once converted to C++.
+         */
+        GMX_RELEASE_ASSERT(false, "State copying is currently not implemented in replica exchange");
     }
 }
 
-#define scopy_rvecs(v, n)   copy_rvecs(state->v, state_local->v, n);
-#define scopy_doubles(v, n) copy_doubles(state->v, state_local->v, n);
-#define scopy_reals(v, n) copy_reals(state->v, state_local->v, n);
-#define scopy_ints(v, n)   copy_ints(state->v, state_local->v, n);
-
-static void copy_state_nonatomdata(t_state *state, t_state *state_local)
-{
-    /* When t_state changes, this code should be updated. */
-    int ngtc, nnhpres;
-    ngtc    = state->ngtc * state->nhchainlength;
-    nnhpres = state->nnhpres* state->nhchainlength;
-    scopy_rvecs(box, DIM);
-    scopy_rvecs(box_rel, DIM);
-    scopy_rvecs(boxv, DIM);
-    state_local->veta = state->veta;
-    state_local->vol0 = state->vol0;
-    scopy_rvecs(svir_prev, DIM);
-    scopy_rvecs(fvir_prev, DIM);
-    scopy_rvecs(pres_prev, DIM);
-    scopy_doubles(nosehoover_xi, ngtc);
-    scopy_doubles(nosehoover_vxi, ngtc);
-    scopy_doubles(nhpres_xi, nnhpres);
-    scopy_doubles(nhpres_vxi, nnhpres);
-    scopy_doubles(therm_integral, state->ngtc);
-    scopy_rvecs(x, state->natoms);
-    scopy_rvecs(v, state->natoms);
-    copy_ints(&(state->fep_state), &(state_local->fep_state), 1);
-    scopy_reals(lambda, efptNR);
-}
-
 static void scale_velocities(t_state *state, real fac)
 {
     int i;
 
-    if (state->v)
+    if (as_rvec_array(state->v.data()))
     {
         for (i = 0; i < state->natoms; i++)
         {
@@ -1315,7 +1245,7 @@ gmx_bool replica_exchange(FILE *fplog, const t_commrec *cr, struct gmx_repl_ex *
         }
         else
         {
-            copy_state_nonatomdata(state_local, state);
+            copy_state_serial(state_local, state);
         }
 
         if (MASTER(cr))
@@ -1351,7 +1281,7 @@ gmx_bool replica_exchange(FILE *fplog, const t_commrec *cr, struct gmx_repl_ex *
         if (!DOMAINDECOMP(cr))
         {
             /* Copy the global state to the local state data structure */
-            copy_state_nonatomdata(state, state_local);
+            copy_state_serial(state, state_local);
         }
     }
 
index 7d489bb013bb83d98aa92b4e8192181b8bfb0f3f..5e51e7e106f491bfeb05d82f918b1eac1926a98e 100644 (file)
@@ -44,7 +44,6 @@
 
 #include <algorithm>
 
-#include "gromacs/gmxlib/md_logging.h"
 #include "gromacs/hardware/cpuinfo.h"
 #include "gromacs/hardware/detecthardware.h"
 #include "gromacs/hardware/gpu_hw_info.h"
@@ -57,6 +56,7 @@
 #include "gromacs/topology/topology.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/logger.h"
 #include "gromacs/utility/stringutil.h"
 
 
@@ -258,7 +258,7 @@ static int get_tmpi_omp_thread_division(const gmx_hw_info_t *hwinfo,
 }
 
 
-static int getMaxGpuUsable(FILE *fplog, const t_commrec *cr, const gmx_hw_info_t *hwinfo,
+static int getMaxGpuUsable(const gmx::MDLogger &mdlog, const gmx_hw_info_t *hwinfo,
                            int cutoff_scheme, gmx_bool bUseGpu)
 {
     /* This code relies on the fact that GPU are not detected when GPU
@@ -276,7 +276,7 @@ static int getMaxGpuUsable(FILE *fplog, const t_commrec *cr, const gmx_hw_info_t
         {
             if (hwinfo->gpu_info.n_dev_compatible > 1)
             {
-                md_print_warn(cr, fplog, "More than one compatible GPU is available, but GROMACS can only use one of them. Using a single thread-MPI rank.\n");
+                GMX_LOG(mdlog.warning).asParagraph().appendText("More than one compatible GPU is available, but GROMACS can only use one of them. Using a single thread-MPI rank.");
             }
             return 1;
         }
@@ -345,8 +345,7 @@ int get_nthreads_mpi(const gmx_hw_info_t *hwinfo,
                      gmx_hw_opt_t        *hw_opt,
                      const t_inputrec    *inputrec,
                      const gmx_mtop_t    *mtop,
-                     const t_commrec     *cr,
-                     FILE                *fplog,
+                     const gmx::MDLogger &mdlog,
                      gmx_bool             bUseGpu,
                      bool                 doMembed)
 {
@@ -372,7 +371,7 @@ int get_nthreads_mpi(const gmx_hw_info_t *hwinfo,
             {
                 gmx_fatal(FARGS, "%s However, you asked for more than 1 thread-MPI rank, so mdrun cannot continue. Choose a single rank, or a different algorithm.", message.c_str());
             }
-            md_print_warn(cr, fplog, "%s Choosing to use only a single thread-MPI rank.", message.c_str());
+            GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted("%s Choosing to use only a single thread-MPI rank.", message.c_str());
             return 1;
         }
     }
@@ -401,7 +400,7 @@ int get_nthreads_mpi(const gmx_hw_info_t *hwinfo,
         nthreads_tot_max = nthreads_hw;
     }
 
-    ngpu = getMaxGpuUsable(fplog, cr, hwinfo, inputrec->cutoff_scheme, bUseGpu);
+    ngpu = getMaxGpuUsable(mdlog, hwinfo, inputrec->cutoff_scheme, bUseGpu);
 
     if (inputrec->cutoff_scheme == ecutsGROUP)
     {
@@ -523,7 +522,7 @@ void check_resource_division_efficiency(const gmx_hw_info_t *hwinfo,
                                         const gmx_hw_opt_t  *hw_opt,
                                         gmx_bool             bNtOmpOptionSet,
                                         t_commrec           *cr,
-                                        FILE                *fplog)
+                                        const gmx::MDLogger &mdlog)
 {
 #if GMX_OPENMP && GMX_MPI
     int         nth_omp_min, nth_omp_max, ngpu;
@@ -592,7 +591,7 @@ void check_resource_division_efficiency(const gmx_hw_info_t *hwinfo,
 
             if (bNtOmpOptionSet)
             {
-                md_print_warn(cr, fplog, "NOTE: %s\n", buf);
+                GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted("NOTE: %s", buf);
             }
             else
             {
@@ -640,7 +639,7 @@ void check_resource_division_efficiency(const gmx_hw_info_t *hwinfo,
              */
             if (bNtOmpOptionSet || (bEnvSet && nth_omp_min != nth_omp_max))
             {
-                md_print_warn(cr, fplog, "NOTE: %s\n", buf);
+                GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted("NOTE: %s", buf);
             }
             else
             {
@@ -652,20 +651,14 @@ void check_resource_division_efficiency(const gmx_hw_info_t *hwinfo,
       /* No OpenMP and/or MPI: it doesn't make much sense to check */
     GMX_UNUSED_VALUE(hw_opt);
     GMX_UNUSED_VALUE(bNtOmpOptionSet);
+    GMX_UNUSED_VALUE(cr);
     /* Check if we have more than 1 physical core, if detected,
      * or more than 1 hardware thread if physical cores were not detected.
      */
-#if !GMX_OPENMP && !GMX_MPI
-    if (hwinfo->hardwareTopology->numberOfCores() > 1)
+    if (!GMX_OPENMP && !GMX_MPI && hwinfo->hardwareTopology->numberOfCores() > 1)
     {
-        md_print_warn(cr, fplog, "NOTE: GROMACS was compiled without OpenMP and (thread-)MPI support, can only use a single CPU core\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText("NOTE: GROMACS was compiled without OpenMP and (thread-)MPI support, can only use a single CPU core");
     }
-#else
-    GMX_UNUSED_VALUE(hwinfo);
-    GMX_UNUSED_VALUE(cr);
-    GMX_UNUSED_VALUE(fplog);
-#endif
-
 #endif /* GMX_OPENMP && GMX_MPI */
 }
 
index 0f292aaf63a56386dd871da8ae4b356d53c863fb..5da5c2020c529318f549172d0e72aad7d3a7d3cf 100644 (file)
@@ -46,6 +46,11 @@ struct gmx_mtop_t;
 struct t_commrec;
 struct t_inputrec;
 
+namespace gmx
+{
+class MDLogger;
+}
+
 /* Return the number of threads to use for thread-MPI based on how many
  * were requested, which algorithms we're using,
  * and how many particles there are.
@@ -58,8 +63,7 @@ int get_nthreads_mpi(const gmx_hw_info_t *hwinfo,
                      gmx_hw_opt_t        *hw_opt,
                      const t_inputrec    *inputrec,
                      const gmx_mtop_t    *mtop,
-                     const t_commrec     *cr,
-                     FILE                *fplog,
+                     const gmx::MDLogger &mdlog,
                      gmx_bool             bUseGpu,
                      bool                 doMembed);
 
@@ -74,8 +78,8 @@ int get_nthreads_mpi(const gmx_hw_info_t *hwinfo,
 void check_resource_division_efficiency(const gmx_hw_info_t *hwinfo,
                                         const gmx_hw_opt_t  *hw_opt,
                                         gmx_bool             bNtOmpOptionSet,
-                                        struct t_commrec    *cr,
-                                        FILE                *fplog);
+                                        t_commrec           *cr,
+                                        const gmx::MDLogger &mdlog);
 
 /* Checks we can do when we don't (yet) know the cut-off scheme */
 void check_and_update_hw_opt_1(gmx_hw_opt_t    *hw_opt,
index 560b923ba600d4304b2eea72a1a5d76b7a1f6bfa..38aa03d1477dfe76710f2963321b7342d4944e7f 100644 (file)
 #include "gromacs/fileio/checkpoint.h"
 #include "gromacs/fileio/oenv.h"
 #include "gromacs/fileio/tpxio.h"
-#include "gromacs/gmxlib/md_logging.h"
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/gpu_utils/gpu_utils.h"
 #include "gromacs/hardware/cpuinfo.h"
 #include "gromacs/hardware/detecthardware.h"
+#include "gromacs/hardware/hardwareassign.h"
 #include "gromacs/listed-forces/disre.h"
 #include "gromacs/listed-forces/orires.h"
 #include "gromacs/math/calculate-ewald-splitting-coefficient.h"
 #include "gromacs/mdlib/sighandler.h"
 #include "gromacs/mdlib/sim_util.h"
 #include "gromacs/mdlib/tpi.h"
+#include "gromacs/mdrunutility/mdmodules.h"
 #include "gromacs/mdrunutility/threadaffinity.h"
 #include "gromacs/mdtypes/commrec.h"
+#include "gromacs/mdtypes/energyhistory.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/mdtypes/state.h"
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/filestream.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/gmxmpi.h"
+#include "gromacs/utility/logger.h"
+#include "gromacs/utility/loggerbuilder.h"
 #include "gromacs/utility/pleasecite.h"
 #include "gromacs/utility/smalloc.h"
 
@@ -341,7 +346,6 @@ static void increase_nstlist(FILE *fp, t_commrec *cr,
     real                   rlistWithReferenceNstlist, rlist_inc, rlist_ok, rlist_max;
     real                   rlist_new, rlist_prev;
     size_t                 nstlist_ind = 0;
-    t_state                state_tmp;
     gmx_bool               bBox, bDD, bCont;
     const char            *nstl_gpu = "\nFor optimal performance with a GPU nstlist (now %d) should be larger.\nThe optimum depends on your CPU and GPU resources.\nYou might want to try several nstlist values.\n";
     const char            *nve_err  = "Can not increase nstlist because an NVE ensemble is used";
@@ -480,6 +484,7 @@ static void increase_nstlist(FILE *fp, t_commrec *cr,
             {
                 gmx_incons("Changing nstlist with domain decomposition and unbounded dimensions is not implemented yet");
             }
+            t_state state_tmp {};
             copy_mat(box, state_tmp.box);
             bDD = change_dd_cutoff(cr, &state_tmp, ir, rlist_new);
         }
@@ -597,13 +602,11 @@ static void prepare_verlet_scheme(FILE                           *fplog,
  *
  * with value passed on the command line (if any)
  */
-static void override_nsteps_cmdline(FILE            *fplog,
-                                    gmx_int64_t      nsteps_cmdline,
-                                    t_inputrec      *ir,
-                                    const t_commrec *cr)
+static void override_nsteps_cmdline(const gmx::MDLogger &mdlog,
+                                    gmx_int64_t          nsteps_cmdline,
+                                    t_inputrec          *ir)
 {
     assert(ir);
-    assert(cr);
 
     /* override with anything else than the default -2 */
     if (nsteps_cmdline > -2)
@@ -624,7 +627,7 @@ static void override_nsteps_cmdline(FILE            *fplog,
                     gmx_step_str(nsteps_cmdline, sbuf_steps));
         }
 
-        md_print_warn(cr, fplog, "%s\n", sbuf_msg);
+        GMX_LOG(mdlog.warning).asParagraph().appendText(sbuf_msg);
     }
     else if (nsteps_cmdline < -2)
     {
@@ -674,6 +677,22 @@ static integrator_t *my_integrator(unsigned int ei)
     }
 }
 
+//! Initializes the logger for mdrun.
+static gmx::LoggerOwner buildLogger(FILE *fplog, const t_commrec *cr)
+{
+    gmx::LoggerBuilder builder;
+    if (fplog != NULL)
+    {
+        builder.addTargetFile(gmx::MDLogger::LogLevel::Info, fplog);
+    }
+    if (cr == nullptr || SIMMASTER(cr))
+    {
+        builder.addTargetStream(gmx::MDLogger::LogLevel::Warning,
+                                &gmx::TextOutputFile::standardError());
+    }
+    return builder.build();
+}
+
 int mdrunner(gmx_hw_opt_t *hw_opt,
              FILE *fplog, t_commrec *cr, int nfile,
              const t_filenm fnm[], const gmx_output_env_t *oenv, gmx_bool bVerbose,
@@ -689,7 +708,6 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
 {
     gmx_bool                  bForceUseGPU, bTryUseGPU, bRerunMD;
     t_inputrec               *inputrec;
-    t_state                  *state = NULL;
     matrix                    box;
     gmx_ddbox_t               ddbox = {0};
     int                       npme_major, npme_minor;
@@ -717,7 +735,8 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
 
     /* CAUTION: threads may be started later on in this function, so
        cr doesn't reflect the final parallel state right now */
-    snew(inputrec, 1);
+    gmx::MDModules mdModules;
+    inputrec = mdModules.inputrec();
     snew(mtop, 1);
 
     if (Flags & MD_APPENDFILES)
@@ -730,11 +749,16 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
     bForceUseGPU = (strncmp(nbpu_opt, "gpu", 3) == 0);
     bTryUseGPU   = (strncmp(nbpu_opt, "auto", 4) == 0) || bForceUseGPU;
 
+    // Here we assume that SIMMASTER(cr) does not change even after the
+    // threads are started.
+    gmx::LoggerOwner logOwner(buildLogger(fplog, cr));
+    gmx::MDLogger    mdlog(logOwner.logger());
+
     /* Detect hardware, gather information. This is an operation that is
      * global for this process (MPI rank). */
-    hwinfo = gmx_detect_hardware(fplog, cr, bTryUseGPU);
+    hwinfo = gmx_detect_hardware(mdlog, cr, bTryUseGPU);
 
-    gmx_print_detected_hardware(fplog, cr, hwinfo);
+    gmx_print_detected_hardware(fplog, cr, mdlog, hwinfo);
 
     if (fplog != NULL)
     {
@@ -748,7 +772,9 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
         please_cite(fplog, "Berendsen95a");
     }
 
-    snew(state, 1);
+    std::unique_ptr<t_state> stateInstance = std::unique_ptr<t_state>(new t_state {});
+    t_state *                state         = stateInstance.get();
+
     if (SIMMASTER(cr))
     {
         /* Read (nearly) all data required for the simulation */
@@ -766,7 +792,7 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
              * update the message text and the content of nbnxn_acceleration_supported.
              */
             if (bUseGPU &&
-                !nbnxn_gpu_acceleration_supported(fplog, cr, inputrec, bRerunMD))
+                !nbnxn_gpu_acceleration_supported(mdlog, inputrec, bRerunMD))
             {
                 /* Fallback message printed by nbnxn_acceleration_supported */
                 if (bForceUseGPU)
@@ -789,9 +815,9 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
 
             if (hwinfo->gpu_info.n_dev_compatible > 0)
             {
-                md_print_warn(cr, fplog,
-                              "NOTE: GPU(s) found, but the current simulation can not use GPUs\n"
-                              "      To use a GPU, set the mdp option: cutoff-scheme = Verlet\n");
+                GMX_LOG(mdlog.warning).asParagraph().appendText(
+                        "NOTE: GPU(s) found, but the current simulation can not use GPUs\n"
+                        "      To use a GPU, set the mdp option: cutoff-scheme = Verlet");
             }
 
             if (bForceUseGPU)
@@ -812,7 +838,7 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
     check_and_update_hw_opt_1(hw_opt, cr, npme);
 
     /* Early check for externally set process affinity. */
-    gmx_check_thread_affinity_set(fplog, cr,
+    gmx_check_thread_affinity_set(mdlog, cr,
                                   hw_opt, hwinfo->nthreads_hw_avail, FALSE);
 
 #if GMX_THREAD_MPI
@@ -833,7 +859,7 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
         hw_opt->nthreads_tmpi = get_nthreads_mpi(hwinfo,
                                                  hw_opt,
                                                  inputrec, mtop,
-                                                 cr, fplog, bUseGPU,
+                                                 mdlog, bUseGPU,
                                                  doMembed);
 
         if (hw_opt->nthreads_tmpi > 1)
@@ -950,7 +976,7 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
     /* This needs to be called before read_checkpoint to extend the state */
     init_disres(fplog, mtop, inputrec, cr, fcd, state, repl_ex_nst > 0);
 
-    init_orires(fplog, mtop, state->x, inputrec, cr, &(fcd->orires),
+    init_orires(fplog, mtop, as_rvec_array(state->x.data()), inputrec, cr, &(fcd->orires),
                 state);
 
     if (inputrecDeform(inputrec))
@@ -976,6 +1002,8 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
         tMPI_Thread_mutex_unlock(&deform_init_box_mutex);
     }
 
+    energyhistory_t energyHistory;
+
     if (Flags & MD_STARTFROMCPT)
     {
         /* Check if checkpoint file exists before doing continuation.
@@ -985,7 +1013,7 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
 
         load_checkpoint(opt2fn_master("-cpi", nfile, fnm, cr), &fplog,
                         cr, ddxyz, &npme,
-                        inputrec, state, &bReadEkin,
+                        inputrec, state, &bReadEkin, &energyHistory,
                         (Flags & MD_APPENDFILES),
                         (Flags & MD_APPENDFILESSET),
                         (Flags & MD_REPRODUCIBLE));
@@ -996,14 +1024,16 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
         }
     }
 
-    if (MASTER(cr) && (Flags & MD_APPENDFILES))
+    if (SIMMASTER(cr) && (Flags & MD_APPENDFILES))
     {
         gmx_log_open(ftp2fn(efLOG, nfile, fnm), cr,
                      Flags, &fplog);
+        logOwner = buildLogger(fplog, nullptr);
+        mdlog    = logOwner.logger();
     }
 
     /* override nsteps with value from cmdline */
-    override_nsteps_cmdline(fplog, nsteps_cmdline, inputrec, cr);
+    override_nsteps_cmdline(mdlog, nsteps_cmdline, inputrec);
 
     if (SIMMASTER(cr))
     {
@@ -1034,7 +1064,7 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
                                            dddlb_opt, dlb_scale,
                                            ddcsx, ddcsy, ddcsz,
                                            mtop, inputrec,
-                                           box, state->x,
+                                           box, as_rvec_array(state->x.data()),
                                            &ddbox, &npme_major, &npme_minor);
     }
     else
@@ -1066,19 +1096,20 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
 #if GMX_MPI
     if (MULTISIM(cr))
     {
-        md_print_info(cr, fplog,
-                      "This is simulation %d out of %d running as a composite GROMACS\n"
-                      "multi-simulation job. Setup for this simulation:\n\n",
-                      cr->ms->sim, cr->ms->nsim);
+        GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                "This is simulation %d out of %d running as a composite GROMACS\n"
+                "multi-simulation job. Setup for this simulation:\n",
+                cr->ms->sim, cr->ms->nsim);
     }
-    md_print_info(cr, fplog, "Using %d MPI %s\n",
-                  cr->nnodes,
+    GMX_LOG(mdlog.warning).appendTextFormatted(
+            "Using %d MPI %s\n",
+            cr->nnodes,
 #if GMX_THREAD_MPI
-                  cr->nnodes == 1 ? "thread" : "threads"
+            cr->nnodes == 1 ? "thread" : "threads"
 #else
-                  cr->nnodes == 1 ? "process" : "processes"
+            cr->nnodes == 1 ? "process" : "processes"
 #endif
-                  );
+            );
     fflush(stderr);
 #endif
 
@@ -1088,7 +1119,7 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
     /* Check and update hw_opt for the number of MPI ranks */
     check_and_update_hw_opt_3(hw_opt);
 
-    gmx_omp_nthreads_init(fplog, cr,
+    gmx_omp_nthreads_init(mdlog, cr,
                           hwinfo->nthreads_hw_avail,
                           hw_opt->nthreads_omp,
                           hw_opt->nthreads_omp_pme,
@@ -1106,8 +1137,8 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
     if (bUseGPU)
     {
         /* Select GPU id's to use */
-        gmx_select_gpu_ids(fplog, cr, &hwinfo->gpu_info, bForceUseGPU,
-                           &hw_opt->gpu_opt);
+        gmx_select_rank_gpu_ids(mdlog, cr, &hwinfo->gpu_info, bForceUseGPU,
+                                &hw_opt->gpu_opt);
     }
     else
     {
@@ -1117,11 +1148,11 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
 
     /* check consistency across ranks of things like SIMD
      * support and number of GPUs selected */
-    gmx_check_hw_runconf_consistency(fplog, hwinfo, cr, hw_opt, bUseGPU);
+    gmx_check_hw_runconf_consistency(mdlog, hwinfo, cr, hw_opt, bUseGPU);
 
     /* Now that we know the setup is consistent, check for efficiency */
     check_resource_division_efficiency(hwinfo, hw_opt, Flags & MD_NTOMPSET,
-                                       cr, fplog);
+                                       cr, mdlog);
 
     if (DOMAINDECOMP(cr))
     {
@@ -1168,7 +1199,7 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
         fr          = mk_forcerec();
         fr->hwinfo  = hwinfo;
         fr->gpu_opt = &hw_opt->gpu_opt;
-        init_forcerec(fplog, fr, fcd, inputrec, mtop, cr, box,
+        init_forcerec(fplog, mdlog, fr, fcd, inputrec, mtop, cr, box,
                       opt2fn("-table", nfile, fnm),
                       opt2fn("-tablep", nfile, fnm),
                       getFilenm("-tableb", nfile, fnm),
@@ -1202,7 +1233,7 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
             /* Make molecules whole at start of run */
             if (fr->ePBC != epbcNONE)
             {
-                do_pbc_first_mtop(fplog, inputrec->ePBC, box, mtop, state->x);
+                do_pbc_first_mtop(fplog, inputrec->ePBC, box, mtop, as_rvec_array(state->x.data()));
             }
             if (vsite)
             {
@@ -1210,7 +1241,7 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
                  * for the initial distribution in the domain decomposition
                  * and for the initial shell prediction.
                  */
-                construct_vsites_mtop(vsite, mtop, state->x);
+                construct_vsites_mtop(vsite, mtop, as_rvec_array(state->x.data()));
             }
         }
 
@@ -1230,7 +1261,8 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
         /* This is a PME only node */
 
         /* We don't need the state */
-        done_state(state);
+        stateInstance.reset();
+        state         = NULL;
 
         ewaldcoeff_q  = calc_ewaldcoeff_q(inputrec->rcoulomb, inputrec->ewald_rtol);
         ewaldcoeff_lj = calc_ewaldcoeff_lj(inputrec->rvdw, inputrec->ewald_rtol_lj);
@@ -1243,11 +1275,23 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
          * - which indicates that probably the OpenMP library has changed it
          * since we first checked).
          */
-        gmx_check_thread_affinity_set(fplog, cr,
+        gmx_check_thread_affinity_set(mdlog, cr,
                                       hw_opt, hwinfo->nthreads_hw_avail, TRUE);
 
+        int nthread_local;
+        /* threads on this MPI process or TMPI thread */
+        if (cr->duty & DUTY_PP)
+        {
+            nthread_local = gmx_omp_nthreads_get(emntNonbonded);
+        }
+        else
+        {
+            nthread_local = gmx_omp_nthreads_get(emntPME);
+        }
+
         /* Set the CPU affinity */
-        gmx_set_thread_affinity(fplog, cr, hw_opt, hwinfo);
+        gmx_set_thread_affinity(fplog, mdlog, cr, hw_opt, *hwinfo->hardwareTopology,
+                                nthread_local, nullptr);
     }
 
     /* Initiate PME if necessary,
@@ -1273,7 +1317,9 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
         {
             status = gmx_pme_init(pmedata, cr, npme_major, npme_minor, inputrec,
                                   mtop ? mtop->natoms : 0, nChargePerturbed, nTypePerturbed,
-                                  (Flags & MD_REPRODUCIBLE), nthreads_pme);
+                                  (Flags & MD_REPRODUCIBLE),
+                                  ewaldcoeff_q, ewaldcoeff_lj,
+                                  nthreads_pme);
             if (status != 0)
             {
                 gmx_fatal(FARGS, "Error %d initializing PME", status);
@@ -1309,7 +1355,7 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
         if (inputrec->bRot)
         {
             /* Initialize enforced rotation code */
-            init_rot(fplog, inputrec, nfile, fnm, cr, state->x, state->box, mtop, oenv,
+            init_rot(fplog, inputrec, nfile, fnm, cr, as_rvec_array(state->x.data()), state->box, mtop, oenv,
                      bVerbose, Flags);
         }
 
@@ -1326,12 +1372,12 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
         }
 
         /* Now do whatever the user wants us to do (how flexible...) */
-        my_integrator(inputrec->eI) (fplog, cr, nfile, fnm,
+        my_integrator(inputrec->eI) (fplog, cr, mdlog, nfile, fnm,
                                      oenv, bVerbose,
                                      nstglobalcomm,
                                      vsite, constr,
                                      nstepout, inputrec, mtop,
-                                     fcd, state,
+                                     fcd, state, &energyHistory,
                                      mdatoms, nrnb, wcycle, ed, fr,
                                      repl_ex_nst, repl_ex_nex, repl_ex_seed,
                                      membed,
@@ -1364,11 +1410,17 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
     /* Finish up, write some stuff
      * if rerunMD, don't write last frame again
      */
-    finish_run(fplog, cr,
+    finish_run(fplog, mdlog, cr,
                inputrec, nrnb, wcycle, walltime_accounting,
                fr ? fr->nbv : NULL,
                EI_DYNAMICS(inputrec->eI) && !MULTISIM(cr));
 
+    // Free PME data
+    if (pmedata)
+    {
+        gmx_pme_destroy(pmedata);
+        pmedata = NULL;
+    }
 
     /* Free GPU memory and context */
     free_gpu_resources(fr, cr, &hwinfo->gpu_info, fr ? fr->gpu_opt : NULL);
index 6c5270d3e919639328fb87b9b83bd90aac04afa4..d4763d2f7b25a3422fe4192b104d1655cca79f27 100644 (file)
@@ -60,10 +60,7 @@ gmx_add_gtest_executable(
     # pseudo-library for code for mdrun
     $<TARGET_OBJECTS:mdrun_objlib>
     )
-gmx_register_integration_test(
-    ${testname}
-    ${exename}
-    )
+gmx_register_gtest_test(${testname} ${exename} INTEGRATION_TEST)
 
 set(testname "MdrunMpiTests")
 set(exename "mdrun-mpi-test")
@@ -80,8 +77,4 @@ gmx_add_gtest_executable(
     # pseudo-library for code for mdrun
     $<TARGET_OBJECTS:mdrun_objlib>
     )
-gmx_register_mpi_integration_test(
-    ${testname}
-    ${exename}
-    2
-    )
+gmx_register_gtest_test(${testname} ${exename} MPI_RANKS 2 INTEGRATION_TEST)
index cf1c3ada4ba36f10ee4f030eba1192600862ecbb..5d0760448b990ef85eb5a11b27990d11624cc226 100644 (file)
@@ -59,6 +59,7 @@
 
 #include "testutils/cmdlinetest.h"
 #include "testutils/integrationtests.h"
+#include "testutils/mpitest.h"
 #include "testutils/testoptions.h"
 
 namespace gmx
@@ -73,10 +74,6 @@ namespace test
 namespace
 {
 
-#if GMX_THREAD_MPI || defined(DOXYGEN)
-//! Number of tMPI threads for child mdrun call.
-int g_numThreads = 1;
-#endif
 #if GMX_OPENMP || defined(DOXYGEN)
 //! Number of OpenMP threads for child mdrun call.
 int g_numOpenMPThreads = 1;
@@ -85,10 +82,6 @@ int g_numOpenMPThreads = 1;
 GMX_TEST_OPTIONS(MdrunTestOptions, options)
 {
     GMX_UNUSED_VALUE(options);
-#if GMX_THREAD_MPI
-    options->addOption(IntegerOption("nt").store(&g_numThreads)
-                           .description("Number of thread-MPI threads/ranks for child mdrun calls"));
-#endif
 #if GMX_OPENMP
     options->addOption(IntegerOption("nt_omp").store(&g_numOpenMPThreads)
                            .description("Number of OpenMP threads for child mdrun calls"));
@@ -237,18 +230,14 @@ SimulationRunner::callMdrun(const CommandLine &callerRef)
 
 #if GMX_MPI
 #  if GMX_GPU != GMX_GPU_NONE
-#    if GMX_THREAD_MPI
-    int         numGpusNeeded = g_numThreads;
-#    else   /* Must be real MPI */
-    int         numGpusNeeded = gmx_node_num();
-#    endif
+    const int   numGpusNeeded = getNumberOfTestMpiRanks();
     std::string gpuIdString(numGpusNeeded, '0');
     caller.addOption("-gpu_id", gpuIdString.c_str());
 #  endif
 #endif
 
 #if GMX_THREAD_MPI
-    caller.addOption("-ntmpi", g_numThreads);
+    caller.addOption("-ntmpi", getNumberOfTestMpiRanks());
 #endif
 
 #if GMX_OPENMP
@@ -262,14 +251,7 @@ SimulationRunner::callMdrun(const CommandLine &callerRef)
      * node regardless of the number of ranks, because that's true in
      * Jenkins and for most developers running the tests. */
     int numberOfNodes = 1;
-#if GMX_THREAD_MPI
-    /* Can't use gmx_node_num() because it is only valid after spawn of thread-MPI threads */
-    int numberOfRanks = g_numThreads;
-#elif GMX_LIB_MPI
-    int numberOfRanks = gmx_node_num();
-#else
-    int numberOfRanks = 1;
-#endif
+    int numberOfRanks = getNumberOfTestMpiRanks();
     if (numberOfRanks > numberOfNodes && !gmx_multiple_gpu_per_node_supported())
     {
         if (gmx_node_rank() == 0)
index a3a315563d14cb0f9a0db99e844bcf65c15bdcc7..f2e2c7acfb2d589ed3fa6ba437e00ea410fabd6d 100644 (file)
@@ -82,7 +82,7 @@ TEST_P(MdrunRerun, WithDifferentInputFormats)
  * version. */
 const char *trajectoryFileNames[] = {
     "../../../gromacs/gmxana/legacytests/spc2-traj.trr",
-#if defined GMX_USE_TNG && HAVE_ZLIB
+#if GMX_USE_TNG
     "../../../gromacs/gmxana/legacytests/spc2-traj.tng",
 #endif
     "../../../gromacs/gmxana/legacytests/spc2-traj.xtc",
index 050394cad21d1414062371d17d23364f1cbd6a1d..8d31b68d9feda6b4e3539481823c72d2f5f3a20c 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2013, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -129,7 +129,7 @@ static void MBCallback(t_x11 * /*x11*/, int dlg_mess, int /*item_id*/,
 {
     t_gmx *gmx;
 
-    gmx = (t_gmx *)data;
+    gmx = static_cast<t_gmx *>(data);
     if (dlg_mess == DLG_EXIT)
     {
         hide_mb(gmx);
@@ -155,7 +155,7 @@ static void QuitCB(t_x11 *x11, int dlg_mess, int /*item_id*/,
                    char *set, void *data)
 {
     t_gmx  *gmx;
-    gmx = (t_gmx *)data;
+    gmx = static_cast<t_gmx *>(data);
 
     hide_mb(gmx);
     if (dlg_mess == DLG_EXIT)
@@ -215,7 +215,7 @@ static void ExportCB(t_x11 *x11, int dlg_mess, int item_id,
     t_gmx     *gmx;
     t_dlg     *dlg;
 
-    gmx = (t_gmx *)data;
+    gmx = static_cast<t_gmx *>(data);
     dlg = gmx->dlgs[edExport];
     switch (dlg_mess)
     {
@@ -278,7 +278,7 @@ static void BondsCB(t_x11 *x11, int dlg_mess, int item_id,
     t_gmx     *gmx;
     char      *endptr;
 
-    gmx = (t_gmx *)data;
+    gmx = static_cast<t_gmx *>(data);
     if (ebond == -1)
     {
         ebond = gmx->man->molw->bond_type;
index d9d43e72858b70652205fa5c6e008ba6b6f629cc..5a99f93191d5995074754f122fe049c90e9e6cbf 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -500,7 +500,7 @@ static bool TitleCallBack(t_x11 *x11, XEvent *event, Window /*w*/, void *data)
 {
     t_windata *wd;
 
-    wd = (t_windata *)data;
+    wd = static_cast<t_windata *>(data);
     switch (event->type)
     {
         case Expose:
@@ -525,7 +525,7 @@ static bool ManCallBack(t_x11 *x11, XEvent *event, Window /*w*/, void *data)
     t_manager *man;
     int        width, height;
 
-    man = (t_manager *)data;
+    man = static_cast<t_manager *>(data);
     switch (event->type)
     {
         case ConfigureNotify:
index d2f27ef9d3f9b609d1853058ed92ebcd5d1e3488..f06896d2c94a0b00d99bee01ff2ac61c8cb45d84 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2013, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -61,7 +61,7 @@ static bool MWCallBack(t_x11 *x11, XEvent *event, Window /*w*/, void *data)
     Window    To;
     XEvent    letter;
 
-    mw                          = (t_molwin *)data;
+    mw                          = static_cast<t_molwin *>(data);
     To                          = mw->wd.Parent;
     letter.type                 = ClientMessage;
     letter.xclient.display      = x11->disp;
@@ -284,11 +284,11 @@ static void draw_bond(Display *disp, Window w, GC gc,
 
 int compare_obj(const void *a, const void *b)
 {
-    t_object *oa, *ob;
-    real      z;
+    const t_object *oa, *ob;
+    real            z;
 
-    oa = (t_object *)a;
-    ob = (t_object *)b;
+    oa = static_cast<const t_object *>(a);
+    ob = static_cast<const t_object *>(b);
 
     z = oa->z-ob->z;
 
index 2bd34f4b64dc1b13c057bc8cbc2ed17eabf7fbc6..87eb4495d178599de3dbe56254293a8c859118a1 100644 (file)
 # To help us fund GROMACS development, we humbly ask that you cite
 # the research papers on the package. Check out http://www.gromacs.org.
 
+if (NOT GMX_BUILD_UNITTESTS)
+    gmx_add_missing_tests_notice("Unit tests have not been run. You need to set GMX_BUILD_UNITTESTS=ON if you want to build and run them.")
+    return()
+endif()
+
 include_directories(BEFORE SYSTEM ${GMOCK_INCLUDE_DIRS})
 set(TESTUTILS_SOURCES
     cmdlinetest.cpp
     integrationtests.cpp
     interactivetest.cpp
     mpi-printer.cpp
+    mpitest.cpp
     refdata.cpp
     refdata-xml.cpp
     stringtest.cpp
@@ -58,7 +64,7 @@ add_library(testutils STATIC ${UNITTEST_TARGET_OPTIONS} ${TESTUTILS_SOURCES})
 set(TESTUTILS_LIBS testutils)
 set_property(TARGET testutils APPEND PROPERTY COMPILE_DEFINITIONS "${GMOCK_COMPILE_DEFINITIONS}")
 set_property(TARGET testutils APPEND PROPERTY COMPILE_FLAGS "${GMOCK_COMPILE_FLAGS}")
-target_link_libraries(testutils libgromacs ${GMOCK_LIBRARIES})
+target_link_libraries(testutils libgromacs ${GMX_COMMON_LIBRARIES} ${GMOCK_LIBRARIES})
 
 if(HAVE_TINYXML2)
     include_directories(SYSTEM ${TinyXML2_INCLUDE_DIR})
@@ -67,8 +73,35 @@ else()
     include_directories(BEFORE SYSTEM "../external/tinyxml2")
 endif()
 
+# TODO Use gmx_add_missing_tests_notice() instead of the messages below.
+set(GMX_CAN_RUN_MPI_TESTS 1)
+if (GMX_MPI)
+    set(_an_mpi_variable_had_content 0)
+    foreach(VARNAME MPIEXEC MPIEXEC_NUMPROC_FLAG MPIEXEC_PREFLAGS MPIEXEC_POSTFLAGS)
+        # These variables need a valid value for the test to run
+        # and pass, but conceivably any of them might be valid
+        # with arbitrary (including empty) content. They can't be
+        # valid if they've been populated with the CMake
+        # find_package magic suffix/value "NOTFOUND", though.
+        if (${VARNAME} MATCHES ".*NOTFOUND")
+            message(STATUS "CMake variable ${VARNAME} was not detected to be a valid value. To test GROMACS correctly, check the advice in the install guide.")
+            set(GMX_CAN_RUN_MPI_TESTS 0)
+        endif()
+        if (NOT VARNAME STREQUAL MPIEXEC AND ${VARNAME})
+            set(_an_mpi_variable_had_content 1)
+        endif()
+    endforeach()
+    if(_an_mpi_variable_had_content AND NOT MPIEXEC)
+        message(STATUS "CMake variable MPIEXEC must have a valid value if one of the other related MPIEXEC variables does. To test GROMACS correctly, check the advice in the install guide.")
+        set(GMX_CAN_RUN_MPI_TESTS 0)
+    endif()
+elseif (NOT GMX_THREAD_MPI)
+    set(GMX_CAN_RUN_MPI_TESTS 0)
+endif()
+
 set(TESTUTILS_DIR ${CMAKE_CURRENT_SOURCE_DIR})
 set(TESTUTILS_DIR ${TESTUTILS_DIR} PARENT_SCOPE)
 set(TESTUTILS_LIBS ${TESTUTILS_LIBS} PARENT_SCOPE)
+set(GMX_CAN_RUN_MPI_TESTS ${GMX_CAN_RUN_MPI_TESTS} PARENT_SCOPE)
 
 add_subdirectory(tests)
index faff8af3d290a8416d7635334253bbfd31806762..5b71c5972d47aa80c72139a2bf986bce099e0cff 100644 (file)
@@ -71,7 +71,8 @@ function (gmx_add_gtest_executable EXENAME)
         add_executable(${EXENAME} ${UNITTEST_TARGET_OPTIONS}
             ${_source_files} ${TESTUTILS_DIR}/unittest_main.cpp)
         target_link_libraries(${EXENAME}
-            ${TESTUTILS_LIBS} libgromacs ${GMOCK_LIBRARIES} ${GMX_EXE_LINKER_FLAGS} ${GMX_STDLIB_LIBRARIES})
+            ${TESTUTILS_LIBS} libgromacs ${GMOCK_LIBRARIES}
+            ${GMX_COMMON_LIBRARIES} ${GMX_EXE_LINKER_FLAGS} ${GMX_STDLIB_LIBRARIES})
         set_property(TARGET ${EXENAME}
             APPEND PROPERTY COMPILE_FLAGS "${GMOCK_COMPILE_FLAGS}")
         set_property(TARGET ${EXENAME}
@@ -81,87 +82,59 @@ function (gmx_add_gtest_executable EXENAME)
     endif()
 endfunction()
 
-function (gmx_register_unit_test NAME EXENAME)
-    if (GMX_BUILD_UNITTESTS AND BUILD_TESTING)
-        add_test(NAME ${NAME}
-                 COMMAND ${EXENAME} --gtest_output=xml:${CMAKE_BINARY_DIR}/Testing/Temporary/${NAME}.xml)
-        set_tests_properties(${NAME} PROPERTIES LABELS "GTest;UnitTest")
-        add_dependencies(tests ${EXENAME})
-    endif()
-endfunction ()
-
-# Use this function to register a test binary as an integration test
-function (gmx_register_integration_test NAME EXENAME)
-    if (GMX_BUILD_UNITTESTS AND BUILD_TESTING)
-        add_test(NAME ${NAME}
-                 COMMAND ${EXENAME} --gtest_output=xml:${CMAKE_BINARY_DIR}/Testing/Temporary/${NAME}.xml)
-        set_tests_properties(${testname} PROPERTIES LABELS "IntegrationTest")
-        add_dependencies(tests ${EXENAME})
-
-        # GMX_EXTRA_LIBRARIES might be needed for mdrun integration tests at
-        # some point.
-        # target_link_libraries(${EXENAME} ${GMX_EXTRA_LIBRARIES} ${GMX_STDLIB_LIBRARIES})
-    endif()
-endfunction ()
-
-# Use this function to register a test binary as an integration test
-# that requires MPI. The intended number of MPI ranks is also passed
+# Use this function with MPI_RANKS <N> INTEGRATION_TEST to register a test
+# binary as an integration test that requires MPI. The intended number of MPI
+# ranks is also passed
 #
-# TODO When a test case needs it, generalize the NUMPROC mechanism so
+# TODO When a test case needs it, generalize the MPI_RANKS mechanism so
 # that ctest can run the test binary over a range of numbers of MPI
 # ranks.
-function (gmx_register_mpi_integration_test NAME EXENAME NUMPROC)
+function (gmx_register_gtest_test NAME EXENAME)
     if (GMX_BUILD_UNITTESTS AND BUILD_TESTING)
-        if (GMX_MPI)
-            foreach(VARNAME MPIEXEC MPIEXEC_NUMPROC_FLAG MPIEXEC_PREFLAGS MPIEXEC_POSTFLAGS)
-                # These variables need a valid value for the test to run
-                # and pass, but conceivably any of them might be valid
-                # with arbitrary (including empty) content. They can't be
-                # valid if they've been populated with the CMake
-                # find_package magic suffix/value "NOTFOUND", though.
-                if (${VARNAME} MATCHES ".*NOTFOUND")
-                    message(STATUS "CMake variable ${VARNAME} was not detected to be a valid value. To test GROMACS correctly, check the advice in the install guide.")
-                    set(_cannot_run_mpi_tests 1)
-                endif()
-                if (NOT VARNAME STREQUAL MPIEXEC AND ${VARNAME})
-                    set(_an_mpi_variable_had_content 1)
-                endif()
-            endforeach()
-            if(_an_mpi_variable_had_content AND NOT MPIEXEC)
-                message(STATUS "CMake variable MPIEXEC must have a valid value if one of the other related MPIEXEC variables does. To test GROMACS correctly, check the advice in the install guide.")
-                set(_cannot_run_mpi_tests 1)
+        set(_options INTEGRATION_TEST)
+        set(_one_value_args MPI_RANKS)
+        cmake_parse_arguments(ARG "${_options}" "${_one_value_args}" "" ${ARGN})
+        set(_xml_path ${CMAKE_BINARY_DIR}/Testing/Temporary/${NAME}.xml)
+        set(_labels GTest)
+        set(_timeout 30)
+        if (ARG_INTEGRATION_TEST)
+            list(APPEND _labels IntegrationTest)
+            set(_timeout 120)
+            gmx_get_test_prefix_cmd(_prefix_cmd IGNORE_LEAKS)
+        else()
+            list(APPEND _labels UnitTest)
+            gmx_get_test_prefix_cmd(_prefix_cmd)
+        endif()
+        set(_cmd ${_prefix_cmd} $<TARGET_FILE:${EXENAME}>)
+        if (ARG_MPI_RANKS)
+            if (NOT GMX_CAN_RUN_MPI_TESTS)
+                return()
             endif()
-            if(NOT _cannot_run_mpi_tests)
-                add_test(NAME ${NAME}
-                    COMMAND
-                    ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${NUMPROC}
-                    ${MPIEXEC_PREFLAGS} $<TARGET_FILE:${EXENAME}> ${MPIEXEC_POSTFLAGS}
-                    --gtest_output=xml:${CMAKE_BINARY_DIR}/Testing/Temporary/${NAME}.xml
-                    )
-                set_tests_properties(${testname} PROPERTIES LABELS "MpiIntegrationTest")
-                add_dependencies(tests ${EXENAME})
+            list(APPEND _labels MpiTest)
+            if (GMX_MPI)
+                set(_cmd
+                    ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${ARG_MPI_RANKS}
+                    ${MPIEXEC_PREFLAGS} ${_cmd} ${MPIEXEC_POSTFLAGS})
+            elseif (GMX_THREAD_MPI)
+                list(APPEND _cmd -ntmpi ${ARG_MPI_RANKS})
             endif()
-
-            # GMX_EXTRA_LIBRARIES might be needed for mdrun integration tests at
-            # some point.
-            # target_link_libraries(${EXENAME} ${GMX_EXTRA_LIBRARIES} ${GMX_STDLIB_LIBRARIES})
-        elseif(GMX_THREAD_MPI)
-            add_test(NAME ${NAME}
-                COMMAND
-                $<TARGET_FILE:${EXENAME}> -nt ${NUMPROC}
-                --gtest_output=xml:${CMAKE_BINARY_DIR}/Testing/Temporary/${NAME}.xml
-                )
-            set_tests_properties(${testname} PROPERTIES LABELS "MpiIntegrationTest")
-            add_dependencies(tests ${EXENAME})
-
-            # GMX_EXTRA_LIBRARIES might be needed for mdrun integration tests at
-            # some point.
-            # target_link_libraries(${EXENAME} ${GMX_EXTRA_LIBRARIES} ${GMX_STDLIB_LIBRARIES})
         endif()
+        add_test(NAME ${NAME}
+                 COMMAND ${_cmd} --gtest_output=xml:${_xml_path})
+        set_tests_properties(${NAME} PROPERTIES LABELS "${_labels}")
+        set_tests_properties(${NAME} PROPERTIES TIMEOUT ${_timeout})
+        add_dependencies(tests ${EXENAME})
     endif()
 endfunction ()
 
 function (gmx_add_unit_test NAME EXENAME)
     gmx_add_gtest_executable(${EXENAME} ${ARGN})
-    gmx_register_unit_test(${NAME} ${EXENAME})
+    gmx_register_gtest_test(${NAME} ${EXENAME})
+endfunction()
+
+function (gmx_add_mpi_unit_test NAME EXENAME RANKS)
+    if (GMX_MPI OR (GMX_THREAD_MPI AND GTEST_IS_THREADSAFE))
+        gmx_add_gtest_executable(${EXENAME} MPI ${ARGN})
+        gmx_register_gtest_test(${NAME} ${EXENAME} MPI_RANKS ${RANKS})
+    endif()
 endfunction()
index d70187ea534dda0b7a83c88fb1c3f11e13b5fdbe..eb05df8a9bf31eb6c8b91fc61e229ffb77b624a9 100644 (file)
@@ -358,8 +358,7 @@ void CommandLineTestHelper::setOutputFile(
     }
     std::string fullFilename = impl_->fileManager_.getTemporaryFilePath(suffix);
     args->addOption(option, fullFilename);
-    impl_->outputFiles_.push_back(
-            Impl::OutputFileInfo(option, fullFilename, matcher.createMatcher()));
+    impl_->outputFiles_.emplace_back(option, fullFilename, matcher.createMatcher());
 }
 
 void CommandLineTestHelper::checkOutputFiles(TestReferenceChecker checker) const
index ce8c8541b52d659ddd71e88ca789ff3ed78a9f3a..da76c52d454f96125bff7d5bf5c9edfd6338abe1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -122,19 +122,14 @@ class InteractiveTestHelper::Impl
 
         void checkOutput()
         {
-            const std::string id = formatString("Output%d", static_cast<int>(currentLine_));
-            if (checker_.checkPresent(bHasOutput_, id.c_str()))
+            if (bHasOutput_)
             {
+                const std::string id = formatString("Output%d", static_cast<int>(currentLine_));
                 StringTestBase::checkText(&checker_, currentOutput_, id.c_str());
+                bHasOutput_ = false;
             }
-            bHasOutput_ = false;
             currentOutput_.clear();
         }
-        void checkPendingInput()
-        {
-            const std::string id = formatString("Input%d", static_cast<int>(currentLine_+1));
-            checker_.checkPresent(false, id.c_str());
-        }
 
         TestReferenceChecker             checker_;
         ConstArrayRef<const char *>      inputLines_;
@@ -180,7 +175,7 @@ TextOutputStream &InteractiveTestHelper::outputStream()
 void InteractiveTestHelper::checkSession()
 {
     impl_->checkOutput();
-    impl_->checkPendingInput();
+    impl_->checker_.checkUnusedEntries();
 }
 
 } // namespace test
diff --git a/src/testutils/mpitest.cpp b/src/testutils/mpitest.cpp
new file mode 100644 (file)
index 0000000..959b9c5
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Implements functions in mpitest.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_testutils
+ */
+#include "gmxpre.h"
+
+#include "mpitest.h"
+
+#include "config.h"
+
+#include <gtest/gtest.h>
+
+#include "thread_mpi/tmpi.h"
+
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/ioptionscontainer.h"
+#include "gromacs/utility/basenetwork.h"
+#include "gromacs/utility/exceptions.h"
+
+#include "testutils/testoptions.h"
+
+namespace gmx
+{
+namespace test
+{
+
+#if GMX_THREAD_MPI
+
+namespace
+{
+
+//! Number of tMPI threads.
+int g_numThreads = 1;
+//! \cond
+GMX_TEST_OPTIONS(ThreadMpiTestOptions, options)
+{
+    options->addOption(IntegerOption("ntmpi").store(&g_numThreads)
+                           .description("Number of thread-MPI threads/ranks for the test"));
+}
+//! \endcond
+
+//! Thread entry function for other thread-MPI threads.
+void threadStartFunc(void *data)
+{
+    std::function<void()> &testBody = *reinterpret_cast<std::function<void()> *>(data);
+    try
+    {
+        testBody();
+    }
+    GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
+}
+
+//! Helper function for starting thread-MPI threads for a test.
+bool startThreads(std::function<void()> *testBody)
+{
+    int ret = tMPI_Init_fn(TRUE, g_numThreads, TMPI_AFFINITY_NONE,
+                           threadStartFunc, testBody);
+    return ret == TMPI_SUCCESS;
+}
+
+class InTestGuard
+{
+    public:
+        explicit InTestGuard(bool *inTest) : inTest_(inTest) { *inTest = true; }
+        ~InTestGuard() { *inTest_ = false; }
+
+    private:
+        bool *inTest_;
+};
+
+}       // namespace
+
+//! \cond internal
+bool threadMpiTestRunner(std::function<void()> testBody)
+{
+    static bool inTest = false;
+
+    if (inTest || g_numThreads <= 1)
+    {
+        return true;
+    }
+#if GMX_THREAD_MPI && !GTEST_IS_THREADSAFE
+    ADD_FAILURE()
+    << "Google Test is not thread safe on this platform. "
+    << "Cannot run multi-rank tests with thread-MPI.";
+#else
+    InTestGuard guard(&inTest);
+    if (!startThreads(&testBody))
+    {
+        return false;
+    }
+    try
+    {
+        testBody();
+    }
+    GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
+    tMPI_Finalize();
+#endif
+    return false;
+}
+//! \endcond
+
+#endif
+
+int getNumberOfTestMpiRanks()
+{
+#if GMX_THREAD_MPI
+    return g_numThreads;
+#else
+    return gmx_node_num();
+#endif
+}
+
+} // namespace test
+} // namespace gmx
diff --git a/src/testutils/mpitest.h b/src/testutils/mpitest.h
new file mode 100644 (file)
index 0000000..20629fd
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Helper functions for MPI tests to make thread-MPI look like real MPI.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_testutils
+ */
+#ifndef GMX_TESTUTILS_MPITEST_H
+#define GMX_TESTUTILS_MPITEST_H
+
+#include "config.h"
+
+#include <functional>
+#include <type_traits>
+
+#include "gromacs/utility/basenetwork.h"
+
+namespace gmx
+{
+namespace test
+{
+
+/*! \brief
+ * Returns the number of MPI ranks to use for an MPI test.
+ *
+ * For thread-MPI builds, this will return the requested number of ranks
+ * even before the thread-MPI threads have been started.
+ *
+ * \ingroup module_testutils
+ */
+int getNumberOfTestMpiRanks();
+//! \cond internal
+/*! \brief
+ * Helper function for GMX_MPI_TEST().
+ *
+ * \ingroup module_testutils
+ */
+bool threadMpiTestRunner(std::function<void()> testBody);
+//! \endcond
+
+/*! \brief
+ * Declares that this test is an MPI-enabled unit test.
+ *
+ * \param[in] expectedRankCount Expected number of ranks for this test.
+ *     The test will fail if run with unsupported number of ranks.
+ *
+ * To write unit tests that run under MPI, you need to do a few things:
+ *  - Put GMX_MPI_TEST() as the first statement in your test body and
+ *    specify the number of ranks this test expects.
+ *  - Declare your unit test in CMake with gmx_add_mpi_unit_test().
+ *    Note that all tests in the binary should fulfill the conditions above,
+ *    and work with the same number of ranks.
+ * TODO: Figure out a mechanism for mixing tests with different rank counts in
+ * the same binary (possibly, also MPI and non-MPI tests).
+ *
+ * When you do the above, the following will happen:
+ *  - The test will get compiled only if thread-MPI or real MPI is enabled.
+ *  - The test will get executed on the number of ranks specified.
+ *    If you are using real MPI, the whole test binary is run under MPI and
+ *    test execution across the processes is synchronized (GMX_MPI_TEST()
+ *    actually has no effect in this case, the synchronization is handled at a
+ *    higher level).
+ *    If you are using thread-MPI, GMX_MPI_TEST() is required and it
+ *    initializes thread-MPI with the specified number of threads and runs the
+ *    rest of the test on each of the threads.
+ *
+ * You need to be extra careful for variables in the test fixture, if you use
+ * one: when run under thread-MPI, these will be shared across all the ranks,
+ * while under real MPI, these are naturally different for each process.
+ * Local variables in the test body are private to each rank in both cases.
+ *
+ * Currently, it is not possible to specify the number of ranks as one, because
+ * that will lead to problems with (at least) thread-MPI, but such tests can be
+ * written as serial tests anyways.
+ *
+ * \ingroup module_testutils
+ */
+#if GMX_THREAD_MPI
+#define GMX_MPI_TEST(expectedRankCount) \
+    do { \
+        ASSERT_EQ(expectedRankCount, ::gmx::test::getNumberOfTestMpiRanks()); \
+        typedef std::remove_reference<decltype(*this)>::type MyTestClass; \
+        if (!::gmx::test::threadMpiTestRunner(std::bind(&MyTestClass::TestBody, this))) \
+        { \
+            return; \
+        } \
+    } while (0)
+#else
+#define GMX_MPI_TEST(expectedRankCount) \
+    ASSERT_EQ(expectedRankCount, ::gmx::test::getNumberOfTestMpiRanks())
+#endif
+
+} // namespace test
+} // namespace gmx
+
+#endif
index 493771c866b5a6b1c565b16d4d9759d124f01e64..ca933a5a82d03b1344af645cd747b8be3bf6b35c 100644 (file)
@@ -52,6 +52,7 @@
 
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/strconvert.h"
 #include "gromacs/utility/stringutil.h"
 
 #include "testutils/refdata-impl.h"
@@ -143,27 +144,13 @@ class ExactStringBlockChecker : public IReferenceDataEntryChecker
         std::string  value_;
 };
 
-//! Helper function to parse a floating-point value.
-// TODO: Move this into src/gromacs/utility/, and consolidate with similar code
-// elsewhere.
-double convertDouble(const std::string &value)
-{
-    char   *endptr;
-    double  convertedValue = std::strtod(value.c_str(), &endptr);
-    // TODO: Check for overflow
-    if (*endptr != '\0')
-    {
-        GMX_THROW(InvalidInputError("Invalid floating-point value: " + value));
-    }
-    return convertedValue;
-}
 
 //! Helper function to parse a floating-point reference data value.
 double convertDoubleReferenceValue(const std::string &value)
 {
     try
     {
-        return convertDouble(value);
+        return fromString<double>(value);
     }
     catch (const InvalidInputError &ex)
     {
@@ -224,7 +211,7 @@ class FloatingPointFromStringChecker : public IReferenceDataEntryChecker
         virtual ::testing::AssertionResult
         checkEntry(const ReferenceDataEntry &entry, const std::string &fullId) const
         {
-            FloatType               value    = static_cast<FloatType>(convertDouble(value_));
+            FloatType               value    = fromString<FloatType>(value_);
             FloatType               refValue = static_cast<FloatType>(convertDoubleReferenceValue(entry.value()));
             FloatingPointDifference diff(refValue, value);
             if (tolerance_.isWithin(diff))
@@ -244,6 +231,41 @@ class FloatingPointFromStringChecker : public IReferenceDataEntryChecker
         FloatingPointTolerance  tolerance_;
 };
 
+template <typename ValueType>
+class ValueExtractor : public IReferenceDataEntryChecker
+{
+    public:
+        explicit ValueExtractor(ValueType *value)
+            : value_(value)
+        {
+        }
+
+        virtual void fillEntry(ReferenceDataEntry *) const
+        {
+            GMX_THROW(TestException("Extracting value from non-existent reference data entry"));
+        }
+        virtual ::testing::AssertionResult
+        checkEntry(const ReferenceDataEntry &entry, const std::string &) const
+        {
+            extractValue(entry.value());
+            return ::testing::AssertionSuccess();
+        }
+
+        void extractValue(const std::string &value) const
+        {
+            *value_ = fromString<ValueType>(value);
+        }
+
+    private:
+        ValueType *value_;
+};
+
+template <> inline void
+ValueExtractor<std::string>::extractValue(const std::string &value) const
+{
+    *value_ = value;
+}
+
 } // namespace test
 } // namespace gmx
 
index 4d80baeee37727bd76db95255b0011e7140127ca..3ac5b644c9b20d070a038440560d8527386a24f7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -67,7 +67,7 @@ class ReferenceDataEntry
 
         ReferenceDataEntry(const char *type, const char *id)
             : type_(type), id_(id != NULL ? id : ""), isTextBlock_(false),
-              correspondingOutputEntry_(NULL)
+              hasBeenChecked_(false), correspondingOutputEntry_(NULL)
         {
         }
 
@@ -132,6 +132,18 @@ class ReferenceDataEntry
             return prev != children_.end();
         }
 
+        bool hasBeenChecked() const { return hasBeenChecked_; }
+        void setChecked() { hasBeenChecked_ = true; }
+
+        void setCheckedIncludingChildren()
+        {
+            setChecked();
+            for (const auto &child : children_)
+            {
+                child->setCheckedIncludingChildren();
+            }
+        }
+
         EntryPointer cloneToOutputEntry()
         {
             EntryPointer entry(new ReferenceDataEntry(type_.c_str(), id_.c_str()));
@@ -179,6 +191,7 @@ class ReferenceDataEntry
         std::string         value_;
         bool                isTextBlock_;
         ChildList           children_;
+        bool                hasBeenChecked_;
         ReferenceDataEntry *correspondingOutputEntry_;
 };
 
index 2afd1ec41ce81d46c591da5175b16f8d23ccbefe..9a37881d871baff25aaaba55c12c1c507c31aa93 100644 (file)
 #include "gromacs/options/ioptionscontainer.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/keyvaluetree.h"
 #include "gromacs/utility/path.h"
 #include "gromacs/utility/real.h"
 #include "gromacs/utility/stringutil.h"
+#include "gromacs/utility/variant.h"
 
 #include "testutils/refdata-checkers.h"
 #include "testutils/refdata-impl.h"
@@ -203,6 +205,67 @@ class ReferenceDataTestEventListener : public ::testing::EmptyTestEventListener
         }
 };
 
+//! Formats a path to a reference data entry with a non-null id.
+std::string formatEntryPath(const std::string &prefix, const std::string &id)
+{
+    return prefix + "/" + id;
+}
+
+//! Formats a path to a reference data entry with a null id.
+std::string formatSequenceEntryPath(const std::string &prefix, int seqIndex)
+{
+    return formatString("%s/[%d]", prefix.c_str(), seqIndex+1);
+}
+
+//! Finds all entries that have not been checked under a given root.
+void gatherUnusedEntries(const ReferenceDataEntry &root,
+                         const std::string        &rootPath,
+                         std::vector<std::string> *unusedPaths)
+{
+    if (!root.hasBeenChecked())
+    {
+        unusedPaths->push_back(rootPath);
+        return;
+    }
+    int seqIndex = 0;
+    for (const auto &child : root.children())
+    {
+        std::string path;
+        if (child->id().empty())
+        {
+            path = formatSequenceEntryPath(rootPath, seqIndex);
+            ++seqIndex;
+        }
+        else
+        {
+            path = formatEntryPath(rootPath, child->id());
+        }
+        gatherUnusedEntries(*child, path, unusedPaths);
+    }
+}
+
+//! Produces a GTest assertion of any entries under given root have not been checked.
+void checkUnusedEntries(const ReferenceDataEntry &root, const std::string &rootPath)
+{
+    std::vector<std::string> unusedPaths;
+    gatherUnusedEntries(root, rootPath, &unusedPaths);
+    if (!unusedPaths.empty())
+    {
+        std::string paths;
+        if (unusedPaths.size() > 5)
+        {
+            paths = joinStrings(unusedPaths.begin(), unusedPaths.begin() + 5, "\n  ");
+            paths = "  " + paths + "\n  ...";
+        }
+        else
+        {
+            paths = joinStrings(unusedPaths.begin(), unusedPaths.end(), "\n  ");
+            paths = "  " + paths;
+        }
+        ADD_FAILURE() << "Reference data items not used in test:" << std::endl << paths;
+    }
+}
+
 }       // namespace
 
 void initReferenceData(IOptionsContainer *options)
@@ -276,18 +339,29 @@ TestReferenceDataImpl::TestReferenceDataImpl(
 
 void TestReferenceDataImpl::onTestEnd(bool testPassed)
 {
+    if (!bInUse_)
+    {
+        return;
+    }
     // TODO: Only write the file with update-changed if there were actual changes.
-    if (testPassed && bInUse_ && outputRootEntry_)
+    if (outputRootEntry_)
     {
-        std::string dirname = Path::getParentPath(fullFilename_);
-        if (!Directory::exists(dirname))
+        if (testPassed)
         {
-            if (Directory::create(dirname) != 0)
+            std::string dirname = Path::getParentPath(fullFilename_);
+            if (!Directory::exists(dirname))
             {
-                GMX_THROW(TestException("Creation of reference data directory failed: " + dirname));
+                if (Directory::create(dirname) != 0)
+                {
+                    GMX_THROW(TestException("Creation of reference data directory failed: " + dirname));
+                }
             }
+            writeReferenceDataFile(fullFilename_, *outputRootEntry_);
         }
-        writeReferenceDataFile(fullFilename_, *outputRootEntry_);
+    }
+    else if (compareRootEntry_)
+    {
+        checkUnusedEntries(*compareRootEntry_, "");
     }
 }
 
@@ -310,6 +384,8 @@ class TestReferenceChecker::Impl
         static const char * const    cBooleanNodeName;
         //! String constant for naming XML elements for string values.
         static const char * const    cStringNodeName;
+        //! String constant for naming XML elements for unsigned char values.
+        static const char * const    cUCharNodeName;
         //! String constant for naming XML elements for integer values.
         static const char * const    cIntegerNodeName;
         //! String constant for naming XML elements for int64 values.
@@ -322,6 +398,8 @@ class TestReferenceChecker::Impl
         static const char * const    cIdAttrName;
         //! String constant for naming compounds for vectors.
         static const char * const    cVectorType;
+        //! String constant for naming compounds for key-value tree objects.
+        static const char * const    cObjectType;
         //! String constant for naming compounds for sequences.
         static const char * const    cSequenceType;
         //! String constant for value identifier for sequence length.
@@ -468,19 +546,21 @@ class TestReferenceChecker::Impl
         /*! \brief
          * Current number of unnamed elements in a sequence.
          *
-         * It is the index of the next added unnamed element.
+         * It is the index of the current unnamed element.
          */
         int                     seqIndex_;
 };
 
 const char *const TestReferenceChecker::Impl::cBooleanNodeName    = "Bool";
 const char *const TestReferenceChecker::Impl::cStringNodeName     = "String";
+const char *const TestReferenceChecker::Impl::cUCharNodeName      = "UChar";
 const char *const TestReferenceChecker::Impl::cIntegerNodeName    = "Int";
 const char *const TestReferenceChecker::Impl::cInt64NodeName      = "Int64";
 const char *const TestReferenceChecker::Impl::cUInt64NodeName     = "UInt64";
 const char *const TestReferenceChecker::Impl::cRealNodeName       = "Real";
 const char *const TestReferenceChecker::Impl::cIdAttrName         = "Name";
 const char *const TestReferenceChecker::Impl::cVectorType         = "Vector";
+const char *const TestReferenceChecker::Impl::cObjectType         = "Object";
 const char *const TestReferenceChecker::Impl::cSequenceType       = "Sequence";
 const char *const TestReferenceChecker::Impl::cSequenceLengthName = "Length";
 
@@ -488,7 +568,7 @@ const char *const TestReferenceChecker::Impl::cSequenceLengthName = "Length";
 TestReferenceChecker::Impl::Impl(bool initialized)
     : initialized_(initialized), defaultTolerance_(defaultRealTolerance()),
       compareRootEntry_(NULL), outputRootEntry_(NULL),
-      updateMismatchingEntries_(false), bSelfTestMode_(false), seqIndex_(0)
+      updateMismatchingEntries_(false), bSelfTestMode_(false), seqIndex_(-1)
 {
 }
 
@@ -498,11 +578,11 @@ TestReferenceChecker::Impl::Impl(const std::string &path,
                                  ReferenceDataEntry *outputRootEntry,
                                  bool updateMismatchingEntries, bool bSelfTestMode,
                                  const FloatingPointTolerance &defaultTolerance)
-    : initialized_(true), defaultTolerance_(defaultTolerance), path_(path + "/"),
+    : initialized_(true), defaultTolerance_(defaultTolerance), path_(path),
       compareRootEntry_(compareRootEntry), outputRootEntry_(outputRootEntry),
       lastFoundEntry_(compareRootEntry->children().end()),
       updateMismatchingEntries_(updateMismatchingEntries),
-      bSelfTestMode_(bSelfTestMode), seqIndex_(0)
+      bSelfTestMode_(bSelfTestMode), seqIndex_(-1)
 {
 }
 
@@ -510,15 +590,16 @@ TestReferenceChecker::Impl::Impl(const std::string &path,
 std::string
 TestReferenceChecker::Impl::appendPath(const char *id) const
 {
-    std::string printId = (id != NULL) ? id : formatString("[%d]", seqIndex_);
-    return path_ + printId;
+    return id != nullptr
+           ? formatEntryPath(path_, id)
+           : formatSequenceEntryPath(path_, seqIndex_);
 }
 
 
 ReferenceDataEntry *TestReferenceChecker::Impl::findEntry(const char *id)
 {
     ReferenceDataEntry::ChildIterator entry = compareRootEntry_->findChild(id, lastFoundEntry_);
-    seqIndex_ = (id == NULL) ? seqIndex_+1 : 0;
+    seqIndex_ = (id == nullptr) ? seqIndex_+1 : -1;
     if (compareRootEntry_->isValidChild(entry))
     {
         lastFoundEntry_ = entry;
@@ -556,6 +637,7 @@ TestReferenceChecker::Impl::processItem(const char *type, const char *id,
         return ::testing::AssertionFailure()
                << "Reference data item " << fullId << " not found";
     }
+    entry->setChecked();
     ::testing::AssertionResult result(checkEntry(*entry, fullId, type, checker));
     if (outputRootEntry_ != NULL && entry->correspondingOutputEntry() == NULL)
     {
@@ -616,6 +698,7 @@ TestReferenceChecker TestReferenceData::rootChecker()
     {
         return TestReferenceChecker(new TestReferenceChecker::Impl(true));
     }
+    impl_->compareRootEntry_->setChecked();
     return TestReferenceChecker(
             new TestReferenceChecker::Impl("", impl_->compareRootEntry_.get(),
                                            impl_->outputRootEntry_.get(),
@@ -672,6 +755,17 @@ void TestReferenceChecker::setDefaultTolerance(
 }
 
 
+void TestReferenceChecker::checkUnusedEntries()
+{
+    if (impl_->compareRootEntry_)
+    {
+        gmx::test::checkUnusedEntries(*impl_->compareRootEntry_, impl_->path_);
+        // Mark them checked so that they are reported only once.
+        impl_->compareRootEntry_->setCheckedIncludingChildren();
+    }
+}
+
+
 bool TestReferenceChecker::checkPresent(bool bPresent, const char *id)
 {
     if (impl_->shouldIgnore() || impl_->outputRootEntry_ != NULL)
@@ -712,6 +806,7 @@ TestReferenceChecker TestReferenceChecker::checkCompound(const char *type, const
         ADD_FAILURE() << "Reference data item " << fullId << " not found";
         return TestReferenceChecker(new Impl(true));
     }
+    entry->setChecked();
     if (impl_->updateMismatchingEntries_)
     {
         entry->makeCompound(type);
@@ -793,6 +888,12 @@ void TestReferenceChecker::checkTextBlock(const std::string &value,
 }
 
 
+void TestReferenceChecker::checkUChar(unsigned char value, const char *id)
+{
+    EXPECT_PLAIN(impl_->processItem(Impl::cUCharNodeName, id,
+                                    ExactStringChecker(formatString("%d", value))));
+}
+
 void TestReferenceChecker::checkInteger(int value, const char *id)
 {
     EXPECT_PLAIN(impl_->processItem(Impl::cIntegerNodeName, id,
@@ -871,6 +972,64 @@ void TestReferenceChecker::checkVector(const double value[3], const char *id)
 }
 
 
+void TestReferenceChecker::checkVariant(const Variant &variant, const char *id)
+{
+    if (variant.isType<bool>())
+    {
+        checkBoolean(variant.cast<bool>(), id);
+    }
+    else if (variant.isType<int>())
+    {
+        checkInteger(variant.cast<int>(), id);
+    }
+    else if (variant.isType<float>())
+    {
+        checkFloat(variant.cast<float>(), id);
+    }
+    else if (variant.isType<double>())
+    {
+        checkDouble(variant.cast<double>(), id);
+    }
+    else if (variant.isType<std::string>())
+    {
+        checkString(variant.cast<std::string>(), id);
+    }
+    else
+    {
+        GMX_THROW(TestException("Unsupported variant type"));
+    }
+}
+
+
+void TestReferenceChecker::checkKeyValueTreeObject(const KeyValueTreeObject &tree, const char *id)
+{
+    TestReferenceChecker compound(checkCompound(Impl::cObjectType, id));
+    for (const auto &prop : tree.properties())
+    {
+        compound.checkKeyValueTreeValue(prop.value(), prop.key().c_str());
+    }
+    compound.checkUnusedEntries();
+}
+
+
+void TestReferenceChecker::checkKeyValueTreeValue(const KeyValueTreeValue &value, const char *id)
+{
+    if (value.isObject())
+    {
+        checkKeyValueTreeObject(value.asObject(), id);
+    }
+    else if (value.isArray())
+    {
+        const auto &values = value.asArray().values();
+        checkSequence(values.begin(), values.end(), id);
+    }
+    else
+    {
+        checkVariant(value.asVariant(), id);
+    }
+}
+
+
 TestReferenceChecker
 TestReferenceChecker::checkSequenceCompound(const char *id, size_t length)
 {
@@ -879,5 +1038,70 @@ TestReferenceChecker::checkSequenceCompound(const char *id, size_t length)
     return compound;
 }
 
+
+unsigned char TestReferenceChecker::readUChar(const char *id)
+{
+    if (impl_->shouldIgnore())
+    {
+        GMX_THROW(TestException("Trying to read from non-existent reference data value"));
+    }
+    int value = 0;
+    EXPECT_PLAIN(impl_->processItem(Impl::cUCharNodeName, id,
+                                    ValueExtractor<int>(&value)));
+    return value;
+}
+
+
+int TestReferenceChecker::readInteger(const char *id)
+{
+    if (impl_->shouldIgnore())
+    {
+        GMX_THROW(TestException("Trying to read from non-existent reference data value"));
+    }
+    int value = 0;
+    EXPECT_PLAIN(impl_->processItem(Impl::cIntegerNodeName, id,
+                                    ValueExtractor<int>(&value)));
+    return value;
+}
+
+
+float TestReferenceChecker::readFloat(const char *id)
+{
+    if (impl_->shouldIgnore())
+    {
+        GMX_THROW(TestException("Trying to read from non-existent reference data value"));
+    }
+    float value = 0;
+    EXPECT_PLAIN(impl_->processItem(Impl::cRealNodeName, id,
+                                    ValueExtractor<float>(&value)));
+    return value;
+}
+
+
+double TestReferenceChecker::readDouble(const char *id)
+{
+    if (impl_->shouldIgnore())
+    {
+        GMX_THROW(TestException("Trying to read from non-existent reference data value"));
+    }
+    double value = 0;
+    EXPECT_PLAIN(impl_->processItem(Impl::cRealNodeName, id,
+                                    ValueExtractor<double>(&value)));
+    return value;
+}
+
+
+std::string TestReferenceChecker::readString(const char *id)
+{
+    if (impl_->shouldIgnore())
+    {
+        GMX_THROW(TestException("Trying to read from non-existent reference data value"));
+    }
+    std::string value;
+    EXPECT_PLAIN(impl_->processItem(Impl::cStringNodeName, id,
+                                    ValueExtractor<std::string>(&value)));
+    return value;
+}
+
 } // namespace test
 } // namespace gmx
index 99763e12c3f59a08fa8a41e918bd37e8c9cc6484..1fd128ecdc0d3eeb1a111969b281a7415f4caebf 100644 (file)
@@ -56,6 +56,9 @@ namespace gmx
 {
 
 class IOptionsContainer;
+class KeyValueTreeObject;
+class KeyValueTreeValue;
+class Variant;
 
 namespace test
 {
@@ -274,6 +277,22 @@ class TestReferenceChecker
          */
         void setDefaultTolerance(const FloatingPointTolerance &tolerance);
 
+        /*! \brief
+         * Checks that all reference values have been compared against.
+         *
+         * All values under the compound represented by this checker are
+         * checked, and a non-fatal Google Test assertion is produced if some
+         * values have not been used.
+         *
+         * If not called explicitly, the same check will be done for all
+         * reference data values when the test ends.
+         *
+         * This method also marks the values used, so that subsequent checks
+         * (including the check at the end of the test) will not produce
+         * another assertion about the same values.
+         */
+        void checkUnusedEntries();
+
         /*! \brief
          * Checks whether a data item is present.
          *
@@ -329,6 +348,8 @@ class TestReferenceChecker
          * is easier to edit by hand to set the desired output formatting.
          */
         void checkTextBlock(const std::string &value, const char *id);
+        //! Check a single unsigned char value.
+        void checkUChar(unsigned char value, const char *id);
         //! Check a single integer value.
         void checkInteger(int value, const char *id);
         //! Check a single int64 value.
@@ -351,6 +372,35 @@ class TestReferenceChecker
         void checkVector(const double value[3], const char *id);
         //! Check a single floating-point value from a string.
         void checkRealFromString(const std::string &value, const char *id);
+        //! Checks a variant value that contains a supported simple type.
+        void checkVariant(const Variant &value, const char *id);
+        //! Checks a key-value tree rooted at a object.
+        void checkKeyValueTreeObject(const KeyValueTreeObject &tree, const char *id);
+        //! Checks a generic key-value tree value.
+        void checkKeyValueTreeValue(const KeyValueTreeValue &value, const char *id);
+
+        /*! \name Methods to read values from reference data
+         *
+         * These methods assume that a value with the given `id` has already
+         * been created in the test with `check*()` methods, and that it has
+         * the correct type.
+         *
+         * Currently, these methods do not work correctly if the reference data
+         * file does not exist, so a test using them may fail with exceptions
+         * before the reference data has been generated.
+         * \{
+         */
+        //! Reads an unsigned char value.
+        unsigned char readUChar(const char *id);
+        //! Reads an integer value.
+        int readInteger(const char *id);
+        //! Reads a float value.
+        float readFloat(const char *id);
+        //! Reads a double value.
+        double readDouble(const char *id);
+        //! Reads a string value.
+        std::string readString(const char *id);
+        //! \}
 
         /*! \name Overloaded versions of simple checker methods
          *
@@ -416,6 +466,11 @@ class TestReferenceChecker
         {
             checkVector(value, id);
         }
+        //! Check a generic key-value tree value.
+        void checkValue(const KeyValueTreeValue &value, const char *id)
+        {
+            checkKeyValueTreeValue(value, id);
+        }
         /*!\}*/
 
         /*! \brief
index 4d9b499e9eb6a21f6da5541335170f2d8a8d4f21..fe77b048a6035c67925bf7b454378c3e288a12ce 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -193,16 +193,18 @@ gmx_uint64_t relativeToleranceToUlp(FloatType tolerance)
  * FloatingPointDifference
  */
 
-FloatingPointDifference::FloatingPointDifference(float value1, float value2)
+FloatingPointDifference::FloatingPointDifference(float ref, float value)
+    : termMagnitude_(std::abs(ref))
 {
-    initDifference(value1, value2,
+    initDifference(ref, value,
                    &absoluteDifference_, &ulpDifference_, &bSignDifference_);
     bDouble_ = false;
 }
 
-FloatingPointDifference::FloatingPointDifference(double value1, double value2)
+FloatingPointDifference::FloatingPointDifference(double ref, double value)
+    : termMagnitude_(std::abs(ref))
 {
-    initDifference(value1, value2,
+    initDifference(ref, value,
                    &absoluteDifference_, &ulpDifference_, &bSignDifference_);
     bDouble_ = true;
 }
@@ -214,11 +216,29 @@ bool FloatingPointDifference::isNaN() const
 
 std::string FloatingPointDifference::toString() const
 {
-    const double eps = isDouble() ? GMX_DOUBLE_EPS : GMX_FLOAT_EPS;
-    return formatString("%g (%" GMX_PRIu64 " %s-prec. ULPs, rel. %.3g)%s",
+    std::string relDiffStr;
+
+    if (termMagnitude_ > 0)
+    {
+        // If the reference value is finite we calculate the proper quotient
+        relDiffStr = formatString("%.3g", std::abs(absoluteDifference_/termMagnitude_));
+    }
+    else if (absoluteDifference_ == 0.0)
+    {
+        // If the numbers are identical the quotient is strictly NaN here, but
+        // there no reason to worry when we have a perfect match.
+        relDiffStr = formatString("%.3g", 0.0);
+    }
+    else
+    {
+        // If the reference value is zero and numbers are non-identical, relative difference is infinite.
+        relDiffStr = formatString("Inf");
+    }
+
+    return formatString("%g (%" GMX_PRIu64 " %s-prec. ULPs, rel. %s)%s",
                         absoluteDifference_, ulpDifference_,
                         isDouble() ? "double" : "single",
-                        ulpDifference_ * eps,
+                        relDiffStr.c_str(),
                         bSignDifference_ ? ", signs differ" : "");
 }
 
@@ -246,12 +266,24 @@ bool FloatingPointTolerance::isWithin(
         return true;
     }
 
+    // By using smaller-than-or-equal below, we allow the test to pass if
+    // the numbers are identical, even if the term magnitude is 0, which seems
+    // a reasonable thing to do...
+    const double relativeTolerance
+        = difference.isDouble() ? doubleRelativeTolerance_ : singleRelativeTolerance_;
+
+    if (difference.asAbsolute() <= relativeTolerance * difference.termMagnitude())
+    {
+        return true;
+    }
+
     const gmx_uint64_t ulpTolerance
         = difference.isDouble() ? doubleUlpTolerance_ : singleUlpTolerance_;
     if (ulpTolerance < GMX_UINT64_MAX && difference.asUlps() <= ulpTolerance)
     {
         return true;
     }
+
     return false;
 }
 
@@ -260,22 +292,30 @@ std::string FloatingPointTolerance::toString(const FloatingPointDifference &diff
     std::string        result;
     const double       absoluteTolerance
         = difference.isDouble() ? doubleAbsoluteTolerance_ : singleAbsoluteTolerance_;
+    const double       relativeTolerance
+        = difference.isDouble() ? doubleRelativeTolerance_ : singleRelativeTolerance_;
     const gmx_uint64_t ulpTolerance
         = difference.isDouble() ? doubleUlpTolerance_ : singleUlpTolerance_;
-    const double       eps
-        = difference.isDouble() ? GMX_DOUBLE_EPS : GMX_FLOAT_EPS;
 
     if (absoluteTolerance > 0.0)
     {
         result.append(formatString("abs. %g", absoluteTolerance));
     }
+    if (relativeTolerance > 0.0)
+    {
+        if (!result.empty())
+        {
+            result.append(", ");
+        }
+        result.append(formatString("rel. %.3g", relativeTolerance));
+    }
     if (ulpTolerance < GMX_UINT64_MAX)
     {
         if (!result.empty())
         {
             result.append(", ");
         }
-        result.append(formatString("%" GMX_PRIu64 " ULPs (rel. %.3g)", ulpTolerance, ulpTolerance * eps));
+        result.append(formatString("%" GMX_PRIu64 " ULPs", ulpTolerance));
     }
     if (bSignMustMatch_)
     {
@@ -293,10 +333,10 @@ std::string FloatingPointTolerance::toString(const FloatingPointDifference &diff
 FloatingPointTolerance
 relativeToleranceAsFloatingPoint(double magnitude, double tolerance)
 {
-    const double absoluteTolerance = magnitude * tolerance;
+    const double absoluteTolerance = std::abs(magnitude) * tolerance;
     return FloatingPointTolerance(absoluteTolerance, absoluteTolerance,
-                                  relativeToleranceToUlp<float>(tolerance),
-                                  relativeToleranceToUlp<double>(tolerance),
+                                  tolerance, tolerance,
+                                  GMX_UINT64_MAX, GMX_UINT64_MAX,
                                   false);
 }
 //! \endcond
index dc4b68bba235bbd84c57879b12d629f7e49da212..c13c00ec569555c21931e3366ccb36a4bf300f82 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -209,10 +209,30 @@ void processExpectedException(const std::exception &ex);
 class FloatingPointDifference
 {
     public:
-        //! Initializes a single-precision difference.
-        FloatingPointDifference(float value1, float value2);
-        //! Initializes a double-precision difference.
-        FloatingPointDifference(double value1, double value2);
+
+        /*! \brief Initializes a single-precision difference.
+         *
+         *  \param ref    First term in difference
+         *  \param value  Second term in difference
+         *
+         *  For absolute and ULP differences the two parameters are equivalent,
+         *  since the difference is symmetric. For relative differences
+         *  the first term is interpreted as the reference value, from which
+         *  we extract the magnitude to compare with.
+         */
+        FloatingPointDifference(float ref, float value);
+
+        /*! \brief Initializes a double-precision difference.
+         *
+         *  \param ref    First term in difference
+         *  \param value  Second term in difference
+         *
+         *  For absolute and ULP differences the two parameters are equivalent,
+         *  since the difference is symmetric. For relative differences
+         *  the first term is interpreted as the reference value, from which
+         *  we extract the magnitude to compare with.
+         */
+        FloatingPointDifference(double ref, double value);
 
         /*! \brief
          * Whether one or both of the compared values were NaN.
@@ -244,7 +264,13 @@ class FloatingPointDifference
         //! Formats the difference as a string for assertion failure messages.
         std::string toString() const;
 
+        //! Returns the magnitude of the original second term of the difference.
+        double termMagnitude() const { return termMagnitude_; }
+
     private:
+
+        //! Save the magnitude of the reference value for relative (i.e., not ULP) tolerance
+        double       termMagnitude_;
         //! Stores the absolute difference, or NaN if one or both values were NaN.
         double       absoluteDifference_;
         gmx_uint64_t ulpDifference_;
@@ -270,6 +296,9 @@ class FloatingPointDifference
  *    the given tolerance for the check to pass.
  *    Setting the absolute tolerance to zero disables the absolute tolerance
  *    check.
+ *  - _relative tolerance_: the absolute difference between the numbers must
+ *    be smaller than the tolerance multiplied by the first number. Setting
+ *    the relative tolerance to zero disables this check.
  *  - _ULP tolerance_: ULP (units of least precision) difference between the
  *    values must be smaller than the given tolerance for the check to pass.
  *    Setting the ULP tolerance to zero requires exact match.
@@ -279,13 +308,13 @@ class FloatingPointDifference
  *    check (note that this also applies to `0.0` and `-0.0`: a value with a
  *    different sign than the zero will fail the check).
  *
- * Either an absolute or a ULP tolerance must always be specified.
- * If both are specified, then the check passes if either of the tolerances is
- * satisfied.
+ * Either an absolute, relative, or ULP tolerance must always be specified.
+ * If several of them are specified, then the check passes if either of the
+ * tolerances is satisfied.
  *
- * Any combination of absolute and ULP tolerance can be combined with the sign
- * check.  In this case, the sign check must succeed for the check to pass,
- * even if other tolerances are satisfied.
+ * Any combination of absolute, relative, and ULP tolerance can be combined with
+ * the sign check.  In this case, the sign check must succeed for the check to
+ * pass, even if other tolerances are satisfied.
  *
  * The tolerances can be specified separately for single and double precision
  * comparison.  Different initialization functions have different semantics on
@@ -312,6 +341,10 @@ class FloatingPointTolerance
          *     Allowed absolute difference in a single-precision number.
          * \param[in]  doubleAbsoluteTolerance
          *     Allowed absolute difference in a double-precision number.
+         * \param[in]  singleRelativeTolerance
+         *     Allowed relative difference in a single-precision number.
+         * \param[in]  doubleRelativeTolerance
+         *     Allowed relative difference in a double-precision number.
          * \param[in]  singleUlpTolerance
          *     Allowed ULP difference in a single-precision number.
          * \param[in]  doubleUlpTolerance
@@ -321,11 +354,15 @@ class FloatingPointTolerance
          */
         FloatingPointTolerance(float        singleAbsoluteTolerance,
                                double       doubleAbsoluteTolerance,
+                               float        singleRelativeTolerance,
+                               double       doubleRelativeTolerance,
                                gmx_uint64_t singleUlpTolerance,
                                gmx_uint64_t doubleUlpTolerance,
                                bool         bSignMustMatch)
             : singleAbsoluteTolerance_(singleAbsoluteTolerance),
               doubleAbsoluteTolerance_(doubleAbsoluteTolerance),
+              singleRelativeTolerance_(singleRelativeTolerance),
+              doubleRelativeTolerance_(doubleRelativeTolerance),
               singleUlpTolerance_(singleUlpTolerance),
               doubleUlpTolerance_(doubleUlpTolerance),
               bSignMustMatch_(bSignMustMatch)
@@ -345,6 +382,8 @@ class FloatingPointTolerance
     private:
         float        singleAbsoluteTolerance_;
         double       doubleAbsoluteTolerance_;
+        float        singleRelativeTolerance_;
+        double       doubleRelativeTolerance_;
         gmx_uint64_t singleUlpTolerance_;
         gmx_uint64_t doubleUlpTolerance_;
         bool         bSignMustMatch_;
@@ -361,7 +400,7 @@ class FloatingPointTolerance
 static inline FloatingPointTolerance
 ulpTolerance(gmx_uint64_t ulpDiff)
 {
-    return FloatingPointTolerance(0.0, 0.0, ulpDiff, ulpDiff, false);
+    return FloatingPointTolerance(0.0, 0.0, 0.0, 0.0, ulpDiff, ulpDiff, false);
 }
 
 /*! \brief
@@ -371,7 +410,7 @@ ulpTolerance(gmx_uint64_t ulpDiff)
  * \param[in] magnitude  Magnitude of the numbers the computation operates in.
  * \param[in] tolerance  Relative tolerance permitted (e.g. 1e-4).
  *
- * In addition to setting an ULP tolerance equivalent to \p tolerance for both
+ * In addition to setting an relative tolerance for both
  * precisions, this sets the absolute tolerance such that values close to zero
  * (in general, smaller than \p magnitude) do not fail the check if they
  * differ by less than \p tolerance evaluated at \p magnitude.  This accounts
@@ -379,9 +418,6 @@ ulpTolerance(gmx_uint64_t ulpDiff)
  * accuracy of values much less than \p magnitude do not matter for
  * correctness.
  *
- * The ULP tolerance for different precisions will be different to make them
- * both match \p tolerance.
- *
  * \related FloatingPointTolerance
  */
 FloatingPointTolerance
@@ -412,6 +448,7 @@ relativeToleranceAsPrecisionDependentUlp(double       magnitude,
 {
     return FloatingPointTolerance(magnitude*singleUlpDiff*GMX_FLOAT_EPS,
                                   magnitude*doubleUlpDiff*GMX_DOUBLE_EPS,
+                                  0.0, 0.0,
                                   singleUlpDiff, doubleUlpDiff, false);
 }
 
@@ -423,7 +460,7 @@ relativeToleranceAsPrecisionDependentUlp(double       magnitude,
 static inline FloatingPointTolerance
 absoluteTolerance(double tolerance)
 {
-    return FloatingPointTolerance(tolerance, tolerance,
+    return FloatingPointTolerance(tolerance, tolerance, 0.0, 0.0,
                                   GMX_UINT64_MAX, GMX_UINT64_MAX, false);
 }
 
@@ -555,27 +592,6 @@ static inline ::testing::AssertionResult assertEqualWithinTolerance(
 
 //! \}
 
-/*! \name Assertions for NULL comparison
- *
- * These macros should be used instead of `(EXPECT|ASSERT)_EQ(NULL, ...)`,
- * because Google Test doesn't support the NULL comparison with xlC++ 12.1 on
- * BG/Q.
- */
-//! \{
-
-/*! \brief
- * Asserts that a pointer is null.
- *
- * Works exactly like EXPECT_EQ comparing with a null pointer. */
-#define EXPECT_NULL(val) EXPECT_EQ((void *) NULL, val)
-/*! \brief
- * Asserts that a pointer is null.
- *
- * Works exactly like ASSERT_EQ comparing with a null pointer. */
-#define ASSERT_NULL(val) ASSERT_EQ((void *) NULL, val)
-
-//! \}
-
 //! \cond internal
 /*! \internal \brief
  * Helper method for `(EXPECT|ASSERT)_PLAIN`.
index 5844d99966b51f804775c3ae0d5a94ff430a5e56..ef233ddf90ae5c060ad46e02591439468d0ca1b7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -119,7 +119,7 @@ TextOutputStream &TestFileOutputRedirector::standardOutput()
     if (!impl_->stdoutStream_)
     {
         impl_->stdoutStream_.reset(new StringOutputStream);
-        impl_->fileList_.push_back(Impl::FileListEntry("<stdout>", impl_->stdoutStream_));
+        impl_->fileList_.emplace_back("<stdout>", impl_->stdoutStream_);
     }
     return *impl_->stdoutStream_;
 }
@@ -128,7 +128,7 @@ TextOutputStreamPointer
 TestFileOutputRedirector::openTextOutputFile(const char *filename)
 {
     Impl::StringStreamPointer stream(new StringOutputStream);
-    impl_->fileList_.push_back(Impl::FileListEntry(filename, stream));
+    impl_->fileList_.emplace_back(filename, stream);
     return stream;
 }
 
index 83e877d7be942f26d0397b5fe72b7b8aae6173f2..5ade1e5a1d373a388a9cd52023682611c1d77c22 100644 (file)
@@ -168,18 +168,18 @@ void initTestUtils(const char *dataPath, const char *tempPath, bool usesMpi,
     {
         if (!usesMpi && gmx_node_num() > 1)
         {
+            // We cannot continue, since some tests might be using
+            // MPI_COMM_WORLD, which could deadlock if we would only
+            // continue with the master rank here.
             if (gmx_node_rank() == 0)
             {
                 fprintf(stderr, "NOTE: You are running %s on %d MPI ranks, "
                         "but it is does not contain MPI-enabled tests. "
-                        "Rank 0 will run the tests, other ranks will exit.",
+                        "The test will now exit.\n",
                         context.programName(), gmx_node_num());
             }
-            else
-            {
-                finalizeForCommandLine();
-                std::exit(0);
-            }
+            finalizeForCommandLine();
+            std::exit(1);
         }
         g_testContext.reset(new TestProgramContext(context));
         setProgramContext(g_testContext.get());
@@ -198,7 +198,7 @@ void initTestUtils(const char *dataPath, const char *tempPath, bool usesMpi,
         }
         bool        bHelp = false;
         std::string sourceRoot;
-        Options     options(NULL, NULL);
+        Options     options;
         // TODO: A single option that accepts multiple names would be nicer.
         // Also, we recognize -help, but GTest doesn't, which leads to a bit
         // unintuitive behavior.
index 6f8cb9c9b7b69a2d6725456f9623b6e3ff8963ab..3070802cbf1f6398423ba507ab41f43d4a575b9a 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2011,2012,2014,2015, by the GROMACS development team, led by
+# Copyright (c) 2011,2012,2014,2015,2016, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -37,3 +37,6 @@ gmx_add_unit_test(TestUtilsUnitTests testutils-test
                   refdata_tests.cpp
                   testasserts_tests.cpp
                   xvgtest_tests.cpp)
+
+gmx_add_mpi_unit_test(TestUtilsMpiUnitTests testutils-mpi-test 2
+                      mpitest.cpp)
index 974688cdbee435f1ea167e49d97570c430c86aed..eb1ac9914feea3f08121287dc16c47c806bd7089 100644 (file)
@@ -65,7 +65,7 @@ class InteractiveSession
 
         void addOutput(const char *output)
         {
-            events_.push_back(Event(WriteOutput, output));
+            events_.emplace_back(WriteOutput, output);
         }
         void addInputLine(const char *inputLine)
         {
@@ -73,7 +73,7 @@ class InteractiveSession
         }
         void addReadInput()
         {
-            events_.push_back(Event(ReadInput, ""));
+            events_.emplace_back(ReadInput, "");
         }
         void addInput(const char *inputLine)
         {
@@ -84,7 +84,7 @@ class InteractiveSession
         {
             addInputLine(inputLine);
             helper_.setLastNewline(false);
-            events_.push_back(Event(ReadInputNoNewline, ""));
+            events_.emplace_back(ReadInputNoNewline, "");
         }
 
         void run()
similarity index 61%
rename from src/gromacs/mdtypes/energyhistory.cpp
rename to src/testutils/tests/mpitest.cpp
index 12a585a56234283d1c2e64dccfaf8434b33036bc..b810a2597fb83526fcf2db1d2d8cd3ddcdf1790f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015, by the GROMACS development team, led by
+ * Copyright (c) 2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  * To help us fund GROMACS development, we humbly ask that you cite
  * the research papers on the package. Check out http://www.gromacs.org.
  */
-/* This file is completely threadsafe - keep it that way! */
+/*! \internal \file
+ * \brief
+ * Tests for infrastructure for running tests under MPI.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_testutils
+ */
 #include "gmxpre.h"
 
-#include "energyhistory.h"
+#include "testutils/mpitest.h"
 
-#include <cstring>
+#include "config.h"
 
-#include <algorithm>
+#include <gtest/gtest.h>
 
-#include "gromacs/utility/smalloc.h"
+#include "gromacs/utility/basenetwork.h"
+#include "gromacs/utility/gmxmpi.h"
 
-static void done_delta_h_history(delta_h_history_t *dht)
+namespace
 {
-    int i;
-
-    for (i = 0; i < dht->nndh; i++)
-    {
-        sfree(dht->dh[i]);
-    }
-    sfree(dht->dh);
-    sfree(dht->ndh);
-}
 
-void init_energyhistory(energyhistory_t * enerhist)
+class MpiSelfTest : public ::testing::Test
 {
-    enerhist->nener = 0;
+    public:
+        MpiSelfTest() : reached {0, 0}
+        {}
 
-    enerhist->ener_ave     = NULL;
-    enerhist->ener_sum     = NULL;
-    enerhist->ener_sum_sim = NULL;
-    enerhist->dht          = NULL;
+        int reached[2];
+};
 
-    enerhist->nsteps     = 0;
-    enerhist->nsum       = 0;
-    enerhist->nsteps_sim = 0;
-    enerhist->nsum_sim   = 0;
-
-    enerhist->dht = NULL;
-}
-
-void done_energyhistory(energyhistory_t * enerhist)
+TEST_F(MpiSelfTest, Runs)
 {
-    sfree(enerhist->ener_ave);
-    sfree(enerhist->ener_sum);
-    sfree(enerhist->ener_sum_sim);
-
-    if (enerhist->dht != NULL)
+    GMX_MPI_TEST(2);
+#if GMX_THREAD_MPI
+    reached[gmx_node_rank()] = 1;
+    MPI_Barrier(MPI_COMM_WORLD);
+#else
+    int value = 1;
+    MPI_Gather(&value, 1, MPI_INT, reached, 1, MPI_INT, 0, MPI_COMM_WORLD);
+#endif
+    if (gmx_node_rank() == 0)
     {
-        done_delta_h_history(enerhist->dht);
-        sfree(enerhist->dht);
+        EXPECT_EQ(1, reached[0]);
+        EXPECT_EQ(1, reached[1]);
     }
 }
+
+} // namespace
index 0a13555be2cd1b5944aca4d8d47ea109cce0bf90..52b4ba7b0b5ff785772490c6e2bae31a0c99694e 100644 (file)
 
 #include "testutils/refdata.h"
 
+#include <string>
 #include <vector>
 
 #include <gtest/gtest.h>
 #include <gtest/gtest-spi.h>
 
+#include "gromacs/utility/keyvaluetree.h"
+#include "gromacs/utility/keyvaluetreebuilder.h"
+#include "gromacs/utility/variant.h"
+
 #include "testutils/testasserts.h"
 #include "testutils/testexceptions.h"
 
@@ -266,6 +271,203 @@ TEST(ReferenceDataTest, HandlesMissingData)
         TestReferenceChecker checker(data.rootChecker());
         EXPECT_NONFATAL_FAILURE(checker.checkInteger(1, "missing"), "");
         EXPECT_NONFATAL_FAILURE(checker.checkSequenceArray(5, seq, "missing"), "");
+        // Needed to not make the test fail because of unused "int" and "seq".
+        EXPECT_NONFATAL_FAILURE(checker.checkUnusedEntries(), "");
+    }
+}
+
+
+TEST(ReferenceDataTest, HandlesUncheckedData)
+{
+    const int seq[5] = { -1, 3, 5, 2, 4 };
+
+    {
+        TestReferenceData    data(gmx::test::erefdataUpdateAll);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkInteger(1, "int");
+        checker.checkSequenceArray(5, seq, "seq");
+        checker.checkUnusedEntries();
+    }
+    {
+        TestReferenceData    data(gmx::test::erefdataCompare);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkInteger(1, "int");
+        EXPECT_NONFATAL_FAILURE(checker.checkUnusedEntries(), "");
+    }
+}
+
+
+TEST(ReferenceDataTest, HandlesUncheckedDataInSequence)
+{
+    const int seq[5] = { -1, 3, 5, 2, 4 };
+
+    {
+        TestReferenceData    data(gmx::test::erefdataUpdateAll);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkInteger(1, "int");
+        checker.checkSequenceArray(5, seq, "seq");
+        checker.checkUnusedEntries();
+    }
+    {
+        TestReferenceData    data(gmx::test::erefdataCompare);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkInteger(1, "int");
+        EXPECT_NONFATAL_FAILURE(checker.checkSequenceArray(3, seq, "seq"), "");
+        // It might be nicer to not report the unused sequence entries also
+        // here, but both behaviors are quite OK.
+        EXPECT_NONFATAL_FAILURE(checker.checkUnusedEntries(), "");
+    }
+}
+
+
+TEST(ReferenceDataTest, HandlesUncheckedDataInCompound)
+{
+    {
+        TestReferenceData    data(gmx::test::erefdataUpdateAll);
+        TestReferenceChecker checker(data.rootChecker());
+        TestReferenceChecker compound(checker.checkCompound("Compound", "Compound"));
+        compound.checkInteger(1, "int1");
+        compound.checkInteger(2, "int2");
+        compound.checkUnusedEntries();
+        checker.checkInteger(1, "int");
+        checker.checkUnusedEntries();
+    }
+    {
+        TestReferenceData    data(gmx::test::erefdataCompare);
+        TestReferenceChecker checker(data.rootChecker());
+        TestReferenceChecker compound(checker.checkCompound("Compound", "Compound"));
+        compound.checkInteger(1, "int1");
+        EXPECT_NONFATAL_FAILURE(compound.checkUnusedEntries(), "");
+        checker.checkInteger(1, "int");
+        checker.checkUnusedEntries();
+    }
+}
+
+
+TEST(ReferenceDataTest, HandlesVariants)
+{
+    using gmx::Variant;
+    {
+        TestReferenceData    data(gmx::test::erefdataUpdateAll);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkVariant(Variant::create<bool>(true), "bool");
+        checker.checkVariant(Variant::create<int>(1), "int");
+        checker.checkVariant(Variant::create<double>(3.5), "real");
+        checker.checkVariant(Variant::create<std::string>("foo"), "str");
+    }
+    {
+        TestReferenceData    data(gmx::test::erefdataCompare);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkVariant(Variant::create<bool>(true), "bool");
+        checker.checkVariant(Variant::create<int>(1), "int");
+        checker.checkVariant(Variant::create<double>(3.5), "real");
+        checker.checkVariant(Variant::create<std::string>("foo"), "str");
+    }
+}
+
+//! Helper for building a KeyValueTree for testing.
+gmx::KeyValueTreeObject buildKeyValueTree(bool full)
+{
+    gmx::KeyValueTreeBuilder builder;
+    auto                     root = builder.rootObject();
+    auto                     obj  = root.addObject("o");
+    obj.addValue<int>("i", 1);
+    if (full)
+    {
+        obj.addValue<std::string>("s", "x");
+    }
+    auto arr  = root.addUniformArray<int>("a");
+    arr.addValue(2);
+    arr.addValue(3);
+    root.addValue<std::string>("s", "y");
+    return builder.build();
+}
+
+
+TEST(ReferenceDataTest, HandlesKeyValueTree)
+{
+    gmx::KeyValueTreeObject tree = buildKeyValueTree(true);
+    {
+        TestReferenceData    data(gmx::test::erefdataUpdateAll);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkKeyValueTreeObject(tree, "tree");
+    }
+    {
+        TestReferenceData    data(gmx::test::erefdataCompare);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkKeyValueTreeObject(tree, "tree");
+    }
+}
+
+
+TEST(ReferenceDataTest, HandlesKeyValueTreeExtraKey)
+{
+    {
+        TestReferenceData    data(gmx::test::erefdataUpdateAll);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkKeyValueTreeObject(buildKeyValueTree(false), "tree");
+    }
+    {
+        TestReferenceData    data(gmx::test::erefdataCompare);
+        TestReferenceChecker checker(data.rootChecker());
+        EXPECT_NONFATAL_FAILURE(checker.checkKeyValueTreeObject(buildKeyValueTree(true), "tree"), "");
+    }
+}
+
+
+TEST(ReferenceDataTest, HandlesKeyValueTreeMissingKey)
+{
+    {
+        TestReferenceData    data(gmx::test::erefdataUpdateAll);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkKeyValueTreeObject(buildKeyValueTree(true), "tree");
+    }
+    {
+        TestReferenceData    data(gmx::test::erefdataCompare);
+        TestReferenceChecker checker(data.rootChecker());
+        EXPECT_NONFATAL_FAILURE(checker.checkKeyValueTreeObject(buildKeyValueTree(false), "tree"), "");
+    }
+}
+
+
+TEST(ReferenceDataTest, HandlesVariantsWithIncorrectValue)
+{
+    using gmx::Variant;
+    {
+        TestReferenceData    data(gmx::test::erefdataUpdateAll);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkVariant(Variant::create<bool>(true), "bool");
+        checker.checkVariant(Variant::create<int>(1), "int");
+        checker.checkVariant(Variant::create<double>(3.5), "real");
+        checker.checkVariant(Variant::create<std::string>("foo"), "str");
+    }
+    {
+        TestReferenceData    data(gmx::test::erefdataCompare);
+        TestReferenceChecker checker(data.rootChecker());
+        EXPECT_NONFATAL_FAILURE(checker.checkVariant(Variant::create<bool>(false), "bool"), "");
+        EXPECT_NONFATAL_FAILURE(checker.checkVariant(Variant::create<int>(2), "int"), "");
+        EXPECT_NONFATAL_FAILURE(checker.checkVariant(Variant::create<double>(2.5), "real"), "");
+        EXPECT_NONFATAL_FAILURE(checker.checkVariant(Variant::create<std::string>("bar"), "str"), "");
+    }
+}
+
+
+TEST(ReferenceDataTest, HandlesVariantsWithIncorrectType)
+{
+    using gmx::Variant;
+    {
+        TestReferenceData    data(gmx::test::erefdataUpdateAll);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkVariant(Variant::create<bool>(true), "bool");
+        checker.checkVariant(Variant::create<int>(1), "int");
+        checker.checkVariant(Variant::create<double>(3.5), "real");
+    }
+    {
+        TestReferenceData    data(gmx::test::erefdataCompare);
+        TestReferenceChecker checker(data.rootChecker());
+        EXPECT_NONFATAL_FAILURE(checker.checkVariant(Variant::create<int>(1), "bool"), "");
+        EXPECT_NONFATAL_FAILURE(checker.checkVariant(Variant::create<bool>(true), "int"), "");
+        EXPECT_NONFATAL_FAILURE(checker.checkVariant(Variant::create<int>(2), "real"), "");
     }
 }
 
@@ -466,6 +668,25 @@ TEST(ReferenceDataTest, HandlesMultipleComparisonsAgainstNullIds)
 }
 
 
+TEST(ReferenceDataTest, HandlesReadingValues)
+{
+    {
+        TestReferenceData    data(gmx::test::erefdataUpdateAll);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkUChar('A', "char");
+        checker.checkInteger(1, "int");
+        checker.checkString("Test", "string");
+    }
+    {
+        TestReferenceData    data(gmx::test::erefdataCompare);
+        TestReferenceChecker checker(data.rootChecker());
+        EXPECT_EQ('A', checker.readUChar("char"));
+        EXPECT_EQ(1, checker.readInteger("int"));
+        EXPECT_EQ("Test", checker.readString("string"));
+    }
+}
+
+
 TEST(ReferenceDataTest, HandlesUpdateChangedWithoutChanges)
 {
     {
@@ -563,4 +784,24 @@ TEST(ReferenceDataTest, HandlesUpdateChangedWithCompoundChanges)
     }
 }
 
+TEST(ReferenceDataTest, HandlesUpdateChangedWithRemovedEntries)
+{
+    {
+        TestReferenceData    data(gmx::test::erefdataUpdateAll);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkInteger(1, "int");
+        checker.checkString("Test", "string");
+    }
+    {
+        TestReferenceData    data(gmx::test::erefdataUpdateChanged);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkInteger(2, "int");
+    }
+    {
+        TestReferenceData    data(gmx::test::erefdataCompare);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkInteger(2, "int");
+    }
+}
+
 } // namespace
index 5621821b129458020fb8f405f5a766c342aa6d3e..37a336b89b678a058755699b5b947bac3b293baa 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -110,7 +110,7 @@ TEST(XvgTests, CheckMissing)
         gmx::test::TestReferenceData    data(gmx::test::erefdataCompare);
         gmx::test::TestReferenceChecker checker(data.rootChecker());
         gmx::StringInputStream          sis(input);
-        EXPECT_NONFATAL_FAILURE(checkXvgFile(&sis, &checker, XvgMatchSettings()), "absent");
+        EXPECT_NONFATAL_FAILURE(checkXvgFile(&sis, &checker, XvgMatchSettings()), "not used in test");
     }
 }
 
index b69e0c87bb24088bb0317b1b1b9c4769dc15eb09..560232fd3886ad798adda0d251da0cb5dd82d11d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -140,10 +140,7 @@ void checkXvgFile(TextInputStream        *input,
                                   &checkXvgDataPoint);
         ++dataRowCount;
     }
-    if (settings.testData)
-    {
-        dataChecker.checkPresent(false, formatString("Row%d", dataRowCount).c_str());
-    }
+    dataChecker.checkUnusedEntries();
     legendChecker.checkTextBlock(legendText, "XvgLegend");
 }
 
index ebffac5d7b9652d09e2009ebd0e67b14fa79d4f3..5a946bf27df69c596a0ff6f8ca2dda3bf4e200ce 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by
+# Copyright (c) 2012,2013,2014,2015,2016, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -87,10 +87,10 @@ log: ${log}")
     set(REGRESSIONTEST_DOWNLOAD OFF CACHE BOOL "Tests already downloaded. Set to yes to download again" FORCE)
 endif()
 
-if(REGRESSIONTEST_PATH AND (GMX_BLUEGENE OR CMAKE_CROSSCOMPILING OR CMAKE_CONFIGURATION_TYPES OR GMX_BUILD_MDRUN_ONLY))
-    # TODO: It would be nicer to do these before potentially downloading the tests.
-    # Bluegene requires us to compile both front-end and back-end binaries
-    # (single build is insufficient)
+if(REGRESSIONTEST_PATH AND (CMAKE_CROSSCOMPILING OR CMAKE_CONFIGURATION_TYPES OR GMX_BUILD_MDRUN_ONLY))
+    # TODO: It would be nicer to do these checks before potentially downloading the tests.
+    # Cross-compiling toolchains require us to compile both front-end and
+    # back-end binaries to run gmxtest.pl.
     # Testing an mdrun-only builds require supporting binaries from a full build
     message(WARNING
         "With cross-compiling, multi-configuration generators (e.g. Visual Studio), or with mdrun-only builds, running regressiontests from build system is not supported. Please run gmxtest.pl directly.")
@@ -174,11 +174,8 @@ if(REGRESSIONTEST_PATH)
             ENVIRONMENT "PATH=${PATH}")
     endforeach()
 else()
-    add_custom_target(regressiontests-notice
-        ${CMAKE_COMMAND} -E echo "NOTE: Regression tests have not been run. If you want to run them from the build system, get the correct version of the regression tests package and set REGRESSIONTEST_PATH in CMake to point to it, or set REGRESSIONTEST_DOWNLOAD=ON."
-        DEPENDS run-ctest
-        COMMENT "Regression tests not available" VERBATIM)
-    add_dependencies(check regressiontests-notice)
+    gmx_add_missing_tests_notice("Regression tests have not been run. If you want to run them from the build system, get the correct version of the regression tests package and set REGRESSIONTEST_PATH in CMake to point to it, or set REGRESSIONTEST_DOWNLOAD=ON.")
 endif()
 
+gmx_create_missing_tests_notice_target()
 include(CppCheck.cmake)
diff --git a/tests/CheckTarget.cmake b/tests/CheckTarget.cmake
new file mode 100644 (file)
index 0000000..d621cf4
--- /dev/null
@@ -0,0 +1,67 @@
+#
+# This file is part of the GROMACS molecular simulation package.
+#
+# Copyright (c) 2014,2016, by the GROMACS development team, led by
+# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+# and including many others, as listed in the AUTHORS file in the
+# top-level source directory and at http://www.gromacs.org.
+#
+# GROMACS is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1
+# of the License, or (at your option) any later version.
+#
+# GROMACS is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with GROMACS; if not, see
+# http://www.gnu.org/licenses, or write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+#
+# If you want to redistribute modifications to GROMACS, please
+# consider that scientific software is very special. Version
+# control is crucial - bugs must be traceable. We will be happy to
+# consider code for inclusion in the official distribution, but
+# derived work must not be called official GROMACS. Details are found
+# in the README & COPYING files - if they are missing, get the
+# official version at http://www.gromacs.org.
+#
+# To help us fund GROMACS development, we humbly ask that you cite
+# the research papers on the package. Check out http://www.gromacs.org.
+
+# "tests" target builds all the separate test binaries.
+add_custom_target(tests)
+# "run-ctest" is an internal target that actually runs the tests.
+# This is necessary to be able to add separate targets that execute as part
+# of 'make check', but are ensured to be executed after the actual tests.
+add_custom_target(run-ctest
+                  COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
+                  COMMENT "Running all tests"
+                  USES_TERMINAL VERBATIM)
+add_dependencies(run-ctest tests)
+# "check" target builds and runs all tests.
+add_custom_target(check DEPENDS run-ctest)
+
+# Global property for collecting notices to show at the end of the "check"
+# target.
+set_property(GLOBAL PROPERTY GMX_TESTS_NOTICE)
+
+function (gmx_add_missing_tests_notice TEXT)
+    set_property(GLOBAL APPEND PROPERTY GMX_TESTS_NOTICE ${TEXT})
+endfunction()
+
+function (gmx_create_missing_tests_notice_target)
+    get_property(_text GLOBAL PROPERTY GMX_TESTS_NOTICE)
+    set(_cmds)
+    foreach (_line ${_text})
+        list(APPEND _cmds COMMAND ${CMAKE_COMMAND} -E echo "NOTE: ${_line}")
+    endforeach()
+    add_custom_target(missing-tests-notice
+        ${_cmds}
+        DEPENDS run-ctest
+        COMMENT "Some tests not available" VERBATIM)
+    add_dependencies(check missing-tests-notice)
+endfunction()
index 0500bafe8b52fdf9944b7d0cfd3c1bf8139c1faf..61826c1ce25ff2f187ebdb4a97be3e0f0656a834 100644 (file)
@@ -88,12 +88,7 @@ if (CPPCHECK_EXECUTABLE AND UNIX)
         --suppress=invalidscanf
         --suppress=sizeofCalculation
         --suppress=invalidscanf_libc
-        --suppress=missingInclude:src/programs/mdrun/gmx_gpu_utils/gmx_gpu_utils.cu
         --suppress=*:src/external/Random123-1.08/include/Random123/features/compilerfeatures.h
-        --suppress=invalidPointerCast:src/gromacs/mdlib/nbnxn_cuda/nbnxn_cuda_kernel.cuh
-        --suppress=passedByValue:src/gromacs/mdlib/nbnxn_cuda/nbnxn_cuda_kernel.cuh
-        --suppress=passedByValue:src/gromacs/mdlib/nbnxn_cuda/nbnxn_cuda_kernel_utils.cuh
-        --suppress=shiftTooManyBits:src/gromacs/gpu_utils/gpu_utils.cu
         ) 
     set(_cxx_flags
         -D__cplusplus
@@ -105,7 +100,19 @@ if (CPPCHECK_EXECUTABLE AND UNIX)
         --suppress=passedByValue:src/gromacs/simd/tests/*
         --suppress=redundantAssignment:src/gromacs/simd/simd_math.h #seems to be a bug in cppcheck
         --suppress=noExplicitConstructor # can't be selective about this, see http://sourceforge.net/p/cppcheck/discussion/general/thread/db1e4ba7/
+        --suppress=unusedStructMember:src/gromacs/onlinehelp/tests/helpmanager.cpp
+        --suppress=unusedStructMember:src/gromacs/commandline/cmdlinehelpmodule.cpp
+        --suppress=unusedStructMember:src/gromacs/selection/selhelp.cpp
+        --suppress=redundantPointerOp:src/gromacs/fileio/gmxfio-xdr.cpp
+        --suppress=passedByValue # See comment below
+        --suppress=shiftTooManyBits:src/gromacs/gpu_utils/gpu_utils.cu # CUDA kernel launch false positive
         )
+        # Passing non-trivial objects by value is rarely a problem for
+        # GROMACS in performance-sensitive code, and shouldn't be
+        # enforced for types that are intended to be used like value
+        # types (e.g. SIMD wrapper types, ArrayRef) , nor for
+        # move-enabled types. cppcheck isn't sensitive to these
+        # subtleties yet.
 
     # This list will hold the list of all files with cppcheck errors
     # (one per input file)
@@ -115,7 +122,7 @@ if (CPPCHECK_EXECUTABLE AND UNIX)
         set(_target_name cppcheck-${_filename}.${_outputext})
         string(REPLACE "/" "_" _target_name ${_target_name})
         list(APPEND _filelist ${_target_name})
-        if (_filename MATCHES "\\.cpp$")
+        if (_filename MATCHES "\\.cpp$" OR _filename MATCHES "\\.cu$")
             set(_lang CXX)
             set(_lang_flags ${_cxx_flags})
         else()